aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    async with client.rest:
        users = await client.search_users('Crit')

        # Iterate over the users and take the first 5 results.
        for user in users.take(5):
            print(f'{user.name} ({user.code})')

            # Iterate through the users memberships.
            for membership in user.memberships:
                print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    async with client.rest:
 37        users = await client.search_users('Crit')
 38
 39        # Iterate over the users and take the first 5 results.
 40        for user in users.take(5):
 41            print(f'{user.name} ({user.code})')
 42
 43            # Iterate through the users memberships.
 44            for membership in user.memberships:
 45                print(membership.type, membership.id)
 46
 47client.run(main()) # or asyncio.run(main())
 48```
 49
 50Single RESTClient instance.
 51
 52The difference between base client and the REST clients:
 53
 54* No Hight-Level concepts.
 55* All returned data are pure JSON objects from the API.
 56* No object creation.
 57
 58Example
 59-------
 60```py
 61import aiobungie
 62
 63async def main() -> None:
 64    # Using `async with` context manager to close the session properly.
 65    async with aiobungie.RESTClient("TOKEN") as rest:
 66        payload = await rest.fetch_player('Fate怒', 4275)
 67
 68        for membership in payload:
 69            print(membership['membershipId'], membership['iconPath'])
 70
 71import asyncio
 72asyncio.run(main())
 73```
 74
 75REST client pool.
 76
 77A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 78
 79Example
 80-------
 81```py
 82import aiobungie
 83import asyncio
 84
 85pool = aiobungie.RESTPool("token")
 86
 87async def func1() -> None:
 88    async with pool.acquire() as instance:
 89        tokens = await instance.fetch_oauth2_tokens('code')
 90        pool.metadata['tokens'] = tokens
 91
 92# Other instance may access the tokens from pool since its shared.
 93
 94async def func2() -> None:
 95    async with pool.acquire() as instance:
 96        tokens = pool.metadata['tokens']
 97        tokens = await instance.refresh_access_token(tokens.refresh_token)
 98
 99async def main() -> None:
100    await asyncio.gather(func1(), func2())
101
102asyncio.run(main())
103```
104
105Should you use the base client or the REST client?
106This returns to you. For an example if you're building a website.
107
108You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
109Which gives you the freedom to deserialize it and implement your own logic in the front-end.
110
111Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
112"""
113
114
115from __future__ import annotations
116
117from aiobungie import builders
118from aiobungie import crates
119from aiobungie import interfaces
120from aiobungie import traits
121from aiobungie import typedefs
122from aiobungie import url
123from aiobungie.client import Client
124from aiobungie.error import *
125from aiobungie.internal import iterators
126from aiobungie.internal.assets import Image
127from aiobungie.internal.enums import *
128from aiobungie.internal.factory import Factory
129from aiobungie.internal.iterators import *
130from aiobungie.rest import *
131from aiobungie.undefined import UNDEFINED
132from aiobungie.undefined import UndefinedOr
133from aiobungie.undefined import UndefinedType
134
135from ._info import __about__
136from ._info import __author__
137from ._info import __docs__
138from ._info import __email__
139from ._info import __license__
140from ._info import __url__
141from ._info import __version__
142
143# Alias for crate for backwards compatibility.
144crate = crates
145
146# Activity enums
147from .crates.activity import Difficulty
148
149# Components enums
150from .crates.components import ComponentFields
151from .crates.components import ComponentPrivacy
152
153# Entity enums
154from .crates.entity import GatingScope
155from .crates.entity import ObjectiveUIStyle
156from .crates.entity import ValueUIStyle
157
158# Fireteam enums.
159from .crates.fireteams import FireteamActivity
160from .crates.fireteams import FireteamDate
161from .crates.fireteams import FireteamLanguage
162from .crates.fireteams import FireteamPlatform
163
164# Records enums
165from .crates.records import RecordState
166
167__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
57@attrs.define(auto_exc=True)
58class AiobungieError(RuntimeError):
59    """Base exception class that all other errors inherit from."""

Base exception class that all other errors inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
643@typing.final
644class AmmoType(int, Enum):
645    """AN enum for Detyiny 2 ammo types."""
646
647    NONE = 0
648    PRIMARY = 1
649    SPECIAL = 2
650    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
147@attrs.define(auto_exc=True)
148class BadRequest(HTTPError):
149    """Bad requests exceptions."""
150
151    url: typing.Optional[typedefs.StrOrURL]
152    """The URL/endpoint caused this error."""
153
154    body: typing.Any
155    """The response body."""
156
157    headers: multidict.CIMultiDictProxy[str]
158    """The response headers."""
159
160    http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)

Bad requests exceptions.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>)
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = http_status
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
698@typing.final
699class ClanMemberType(int, Enum):
700    """An enum for bungie clan member types."""
701
702    NONE = 0
703    BEGINNER = 1
704    MEMBER = 2
705    ADMIN = 3
706    ACTING_FOUNDER = 4
707    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
474@typing.final
475class Class(int, Enum):
476    """An Enum for Destiny character classes."""
477
478    TITAN = 0
479    HUNTER = 1
480    WARLOCK = 2
481    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  60class Client(traits.ClientApp):
  61    """Standard Bungie API client application.
  62
  63    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  64    and returns `aiobungie.crates` Python object implementations of the responses.
  65
  66    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  67
  68    Example
  69    -------
  70    ```py
  71    import aiobungie
  72
  73    client = aiobungie.Client('...')
  74
  75    async def main():
  76        async with client.rest:
  77            user = await client.fetch_current_user_memberships('...')
  78            print(user)
  79    ```
  80
  81    Parameters
  82    -----------
  83    token: `str`
  84        Your Bungie's API key or Token from the developer's portal.
  85
  86    Other Parameters
  87    ----------------
  88    max_retries : `int`
  89        The max retries number to retry if the request hit a `5xx` status code.
  90    client_secret : `str | None`
  91        An optional application client secret,
  92        This is only needed if you're fetching OAuth2 tokens with this client.
  93    client_id : `int | None`
  94        An optional application client id,
  95        This is only needed if you're fetching OAuth2 tokens with this client.
  96    """
  97
  98    __slots__ = ("_rest", "_factory")
  99
 100    def __init__(
 101        self,
 102        token: str,
 103        /,
 104        client_secret: typing.Optional[str] = None,
 105        client_id: typing.Optional[int] = None,
 106        *,
 107        max_retries: int = 4,
 108    ) -> None:
 109
 110        self._rest = rest_.RESTClient(
 111            token,
 112            client_secret,
 113            client_id,
 114            max_retries=max_retries,
 115        )
 116
 117        self._factory = factory_.Factory(self)
 118
 119    @property
 120    def factory(self) -> factory_.Factory:
 121        return self._factory
 122
 123    @property
 124    def rest(self) -> interfaces.RESTInterface:
 125        return self._rest
 126
 127    @property
 128    def request(self) -> Client:
 129        return self
 130
 131    @property
 132    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 133        return self._rest.metadata
 134
 135    def run(
 136        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 137    ) -> None:
 138        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 139        try:
 140            if not loop.is_running():
 141                loop.set_debug(debug)
 142                loop.run_until_complete(future)
 143
 144        except Exception as exc:
 145            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 146
 147        except KeyboardInterrupt:
 148            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 149            return
 150
 151    # * User methods.
 152
 153    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 154        """Fetch and return a user object of the bungie net user associated with account.
 155
 156        .. warning::
 157            This method requires OAuth2 scope and a Bearer access token.
 158
 159        Parameters
 160        ----------
 161        access_token : `str`
 162            A valid Bearer access token for the authorization.
 163
 164        Returns
 165        -------
 166        `aiobungie.crates.user.User`
 167            A user object includes the Destiny memberships and Bungie.net user.
 168        """
 169        resp = await self.rest.fetch_current_user_memberships(access_token)
 170
 171        return self.factory.deserialize_user(resp)
 172
 173    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 174        """Fetch a Bungie user by their BungieNet id.
 175
 176        .. note::
 177            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 178            for other memberships.
 179
 180        Parameters
 181        ----------
 182        id: `int`
 183            The user id.
 184
 185        Returns
 186        -------
 187        `aiobungie.crates.user.BungieUser`
 188            A Bungie user.
 189
 190        Raises
 191        ------
 192        `aiobungie.error.NotFound`
 193            The user was not found.
 194        """
 195        payload = await self.rest.fetch_bungie_user(id)
 196
 197        return self.factory.deserialize_bungie_user(payload)
 198
 199    async def search_users(
 200        self, name: str, /
 201    ) -> iterators.Iterator[user.SearchableDestinyUser]:
 202        """Search for players and return all players that matches the same name.
 203
 204        Parameters
 205        ----------
 206        name : `buildins.str`
 207            The user name.
 208
 209        Returns
 210        -------
 211        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
 212            A sequence of destiny memberships.
 213        """
 214        payload = await self.rest.search_users(name)
 215
 216        return iterators.Iterator(
 217            [
 218                self.factory.deserialize_searched_user(user)
 219                for user in payload["searchResults"]
 220            ]
 221        )
 222
 223    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 224        """Fetch all available user themes.
 225
 226        Returns
 227        -------
 228        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 229            A sequence of user themes.
 230        """
 231        data = await self.rest.fetch_user_themes()
 232
 233        return self.factory.deserialize_user_themes(data)
 234
 235    async def fetch_hard_types(
 236        self,
 237        credential: int,
 238        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 239        /,
 240    ) -> user.HardLinkedMembership:
 241        """Gets any hard linked membership given a credential.
 242        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 243        Cross Save aware.
 244
 245        Parameters
 246        ----------
 247        credential: `int`
 248            A valid SteamID64
 249        type: `aiobungie.CredentialType`
 250            The credential type. This must not be changed
 251            Since its only credential that works "currently"
 252
 253        Returns
 254        -------
 255        `aiobungie.crates.user.HardLinkedMembership`
 256            Information about the hard linked data.
 257        """
 258
 259        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 260
 261        return user.HardLinkedMembership(
 262            id=int(payload["membershipId"]),
 263            type=enums.MembershipType(payload["membershipType"]),
 264            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 265        )
 266
 267    async def fetch_membership_from_id(
 268        self,
 269        id: int,
 270        /,
 271        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 272    ) -> user.User:
 273        """Fetch Bungie user's memberships from their id.
 274
 275        Notes
 276        -----
 277        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 278        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 279        see `aiobungie.crates.user.DestinyMembership` for more details.
 280        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 281
 282        Parameters
 283        ----------
 284        id : `int`
 285            The user's id.
 286        type : `aiobungie.MembershipType`
 287            The user's membership type.
 288
 289        Returns
 290        -------
 291        `aiobungie.crates.User`
 292            A Bungie user with their membership types.
 293
 294        Raises
 295        ------
 296        aiobungie.NotFound
 297            The requested user was not found.
 298        """
 299        payload = await self.rest.fetch_membership_from_id(id, type)
 300
 301        return self.factory.deserialize_user(payload)
 302
 303    async def fetch_user_credentials(
 304        self, access_token: str, membership_id: int, /
 305    ) -> collections.Sequence[user.UserCredentials]:
 306        """Fetch an array of credential types attached to the requested account.
 307
 308        .. note::
 309            This method require OAuth2 Bearer access token.
 310
 311        Parameters
 312        ----------
 313        access_token : `str`
 314            The bearer access token associated with the bungie account.
 315        membership_id : `int`
 316            The id of the membership to return.
 317
 318        Returns
 319        -------
 320        `collections.Sequence[aiobungie.crates.UserCredentials]`
 321            A sequence of the attached user credentials.
 322
 323        Raises
 324        ------
 325        `aiobungie.Unauthorized`
 326            The access token was wrong or no access token passed.
 327        """
 328        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 329
 330        return self.factory.deserialize_user_credentials(resp)
 331
 332    # * Destiny 2.
 333
 334    async def fetch_profile(
 335        self,
 336        member_id: int,
 337        type: typedefs.IntAnd[enums.MembershipType],
 338        components: list[enums.ComponentType],
 339        auth: typing.Optional[str] = None,
 340    ) -> components.Component:
 341        """
 342        Fetch a bungie profile passing components to the request.
 343
 344        Parameters
 345        ----------
 346        member_id: `int`
 347            The member's id.
 348        type: `aiobungie.MembershipType`
 349            A valid membership type.
 350        components : `list[aiobungie.ComponentType]`
 351            List of profile components to collect and return.
 352
 353        Other Parameters
 354        ----------------
 355        auth : `typing.Optional[str]`
 356            A Bearer access_token to make the request with.
 357            This is optional and limited to components that only requires an Authorization token.
 358
 359        Returns
 360        --------
 361        `aiobungie.crates.Component`
 362            A Destiny 2 player profile with its components.
 363            Only passed components will be available if they exists. Otherwise they will be `None`
 364
 365        Raises
 366        ------
 367        `aiobungie.MembershipTypeError`
 368            The provided membership type was invalid.
 369        """
 370        data = await self.rest.fetch_profile(member_id, type, components, auth)
 371        return self.factory.deserialize_components(data)
 372
 373    async def fetch_linked_profiles(
 374        self,
 375        member_id: int,
 376        member_type: typedefs.IntAnd[enums.MembershipType],
 377        /,
 378        *,
 379        all: bool = False,
 380    ) -> profile.LinkedProfile:
 381        """Returns a summary information about all profiles linked to the requested member.
 382
 383        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 384
 385        .. note::
 386            It will only return linked accounts whose linkages you are allowed to view.
 387
 388        Parameters
 389        ----------
 390        member_id : `int`
 391            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 392        member_type : `aiobungie.MembershipType`
 393            The type for the membership whose linked Destiny account you want to return.
 394
 395        Other Parameters
 396        ----------------
 397        all : `bool`
 398            If provided and set to `True`, All memberships regardless
 399            of whether they're obscured by overrides will be returned,
 400
 401            If provided and set to `False`, Only available memberships will be returned.
 402            The default for this is `False`.
 403
 404        Returns
 405        -------
 406        `aiobungie.crates.profile.LinkedProfile`
 407            A linked profile object.
 408        """
 409        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 410
 411        return self.factory.deserialize_linked_profiles(resp)
 412
 413    async def fetch_player(
 414        self,
 415        name: str,
 416        code: int,
 417        /,
 418        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 419    ) -> collections.Sequence[user.DestinyMembership]:
 420        """Fetch a Destiny 2 player's memberships.
 421
 422        Parameters
 423        -----------
 424        name: `str`
 425            The unique Bungie player name.
 426        code : `int`
 427            The unique Bungie display name code.
 428        type: `aiobungie.internal.enums.MembershipType`
 429            The player's membership type, e,g. XBOX, STEAM, PSN
 430
 431        Returns
 432        --------
 433        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 434            A sequence of the found Destiny 2 player memberships.
 435            An empty sequence will be returned if no one found.
 436
 437        Raises
 438        ------
 439        `aiobungie.MembershipTypeError`
 440            The provided membership type was invalid.
 441        """
 442        resp = await self.rest.fetch_player(name, code, type)
 443
 444        return self.factory.deserialize_destiny_memberships(resp)
 445
 446    async def fetch_character(
 447        self,
 448        member_id: int,
 449        membership_type: typedefs.IntAnd[enums.MembershipType],
 450        character_id: int,
 451        components: list[enums.ComponentType],
 452        auth: typing.Optional[str] = None,
 453    ) -> components.CharacterComponent:
 454        """Fetch a Destiny 2 character.
 455
 456        Parameters
 457        ----------
 458        member_id: `int`
 459            A valid bungie member id.
 460        character_id: `int`
 461            The Destiny character id to retrieve.
 462        membership_type: `aiobungie.internal.enums.MembershipType`
 463            The member's membership type.
 464        components: `list[aiobungie.ComponentType]`
 465            Multiple arguments of character components to collect and return.
 466
 467        Other Parameters
 468        ----------------
 469        auth : `typing.Optional[str]`
 470            A Bearer access_token to make the request with.
 471            This is optional and limited to components that only requires an Authorization token.
 472
 473        Returns
 474        -------
 475        `aiobungie.crates.CharacterComponent`
 476            A Bungie character component.
 477
 478        `aiobungie.MembershipTypeError`
 479            The provided membership type was invalid.
 480        """
 481        resp = await self.rest.fetch_character(
 482            member_id, membership_type, character_id, components, auth
 483        )
 484
 485        return self.factory.deserialize_character_component(resp)
 486
 487    async def fetch_unique_weapon_history(
 488        self,
 489        membership_id: int,
 490        character_id: int,
 491        membership_type: typedefs.IntAnd[enums.MembershipType],
 492    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 493        """Fetch details about unique weapon usage for a character. Includes all exotics.
 494
 495        Parameters
 496        ----------
 497        membership_id : `int`
 498            The Destiny user membership id.
 499        character_id : `int`
 500            The character id to retrieve.
 501        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 502            The Destiny user's membership type.
 503
 504        Returns
 505        -------
 506        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 507            A sequence of the weapon's extended values.
 508        """
 509        resp = await self._rest.fetch_unique_weapon_history(
 510            membership_id, character_id, membership_type
 511        )
 512
 513        return [
 514            self._factory.deserialize_extended_weapon_values(weapon)
 515            for weapon in resp["weapons"]
 516        ]
 517
 518    # * Destiny 2 Activities.
 519
 520    async def fetch_activities(
 521        self,
 522        member_id: int,
 523        character_id: int,
 524        mode: typedefs.IntAnd[enums.GameMode],
 525        *,
 526        membership_type: typedefs.IntAnd[
 527            enums.MembershipType
 528        ] = enums.MembershipType.ALL,
 529        page: int = 0,
 530        limit: int = 250,
 531    ) -> iterators.Iterator[activity.Activity]:
 532        """Fetch a Destiny 2 activity for the specified character id.
 533
 534        Parameters
 535        ----------
 536        member_id: `int`
 537            The user id that starts with `4611`.
 538        character_id: `int`
 539            The id of the character to retrieve the activities for.
 540        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 541            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 542
 543        Other Parameters
 544        ----------------
 545        membership_type: `aiobungie.internal.enums.MembershipType`
 546            The Member ship type, if nothing was passed than it will return all.
 547        page: int
 548            The page number. Default is `0`
 549        limit: int
 550            Limit the returned result. Default is `250`.
 551
 552        Returns
 553        -------
 554        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
 555            An iterator of the player's activities.
 556
 557        Raises
 558        ------
 559        `aiobungie.MembershipTypeError`
 560            The provided membership type was invalid.
 561        """
 562        resp = await self.rest.fetch_activities(
 563            member_id,
 564            character_id,
 565            mode,
 566            membership_type=membership_type,
 567            page=page,
 568            limit=limit,
 569        )
 570
 571        return self.factory.deserialize_activities(resp)
 572
 573    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 574        """Fetch a post activity details.
 575
 576        Parameters
 577        ----------
 578        instance_id: `int`
 579            The activity instance id.
 580
 581        Returns
 582        -------
 583        `aiobungie.crates.PostActivity`
 584           A post activity object.
 585        """
 586        resp = await self.rest.fetch_post_activity(instance_id)
 587
 588        return self.factory.deserialize_post_activity(resp)
 589
 590    async def fetch_aggregated_activity_stats(
 591        self,
 592        character_id: int,
 593        membership_id: int,
 594        membership_type: typedefs.IntAnd[enums.MembershipType],
 595    ) -> iterators.Iterator[activity.AggregatedActivity]:
 596        """Fetch aggregated activity stats for a character.
 597
 598        Parameters
 599        ----------
 600        character_id: `int`
 601            The id of the character to retrieve the activities for.
 602        membership_id: `int`
 603            The id of the user that started with `4611`.
 604        membership_type: `aiobungie.internal.enums.MembershipType`
 605            The Member ship type.
 606
 607        Returns
 608        -------
 609        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
 610            An iterator of the player's activities.
 611
 612        Raises
 613        ------
 614        `aiobungie.MembershipTypeError`
 615            The provided membership type was invalid.
 616        """
 617        resp = await self.rest.fetch_aggregated_activity_stats(
 618            character_id, membership_id, membership_type
 619        )
 620
 621        return self.factory.deserialize_aggregated_activities(resp)
 622
 623    # * Destiny 2 Clans or GroupsV2.
 624
 625    async def fetch_clan_from_id(
 626        self,
 627        id: int,
 628        /,
 629        access_token: typing.Optional[str] = None,
 630    ) -> clans.Clan:
 631        """Fetch a Bungie Clan by its id.
 632
 633        Parameters
 634        -----------
 635        id: `int`
 636            The clan id.
 637
 638        Returns
 639        --------
 640        `aiobungie.crates.Clan`
 641            An Bungie clan.
 642
 643        Raises
 644        ------
 645        `aiobungie.NotFound`
 646            The clan was not found.
 647        """
 648        resp = await self.rest.fetch_clan_from_id(id, access_token)
 649
 650        return self.factory.deserialize_clan(resp)
 651
 652    async def fetch_clan(
 653        self,
 654        name: str,
 655        /,
 656        access_token: typing.Optional[str] = None,
 657        *,
 658        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 659    ) -> clans.Clan:
 660        """Fetch a Clan by its name.
 661        This method will return the first clan found with given name.
 662
 663        Parameters
 664        ----------
 665        name: `str`
 666            The clan name
 667
 668        Other Parameters
 669        ----------------
 670        access_token : `typing.Optional[str]`
 671            An optional access token to make the request with.
 672
 673            If the token was bound to a member of the clan,
 674            This field `aiobungie.crates.Clan.current_user_membership` will be available
 675            and will return the membership of the user who made this request.
 676        type : `aiobungie.GroupType`
 677            The group type, Default is aiobungie.GroupType.CLAN.
 678
 679        Returns
 680        -------
 681        `aiobungie.crates.Clan`
 682            A Bungie clan.
 683
 684        Raises
 685        ------
 686        `aiobungie.NotFound`
 687            The clan was not found.
 688        """
 689        resp = await self.rest.fetch_clan(name, access_token, type=type)
 690
 691        return self.factory.deserialize_clan(resp)
 692
 693    async def fetch_clan_conversations(
 694        self, clan_id: int, /
 695    ) -> collections.Sequence[clans.ClanConversation]:
 696        """Fetch the conversations/chat channels of the given clan id.
 697
 698        Parameters
 699        ----------
 700        clan_id : `int`
 701            The clan id.
 702
 703        Returns
 704        `collections.Sequence[aiobungie.crates.ClanConversation]`
 705            A sequence of the clan chat channels.
 706        """
 707        resp = await self.rest.fetch_clan_conversations(clan_id)
 708
 709        return self.factory.deserialize_clan_conversations(resp)
 710
 711    async def fetch_clan_admins(
 712        self, clan_id: int, /
 713    ) -> iterators.Iterator[clans.ClanMember]:
 714        """Fetch the clan founder and admins.
 715
 716        Parameters
 717        ----------
 718        clan_id : `int`
 719            The clan id.
 720
 721        Returns
 722        -------
 723        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 724            An iterator over the found clan admins and founder.
 725
 726        Raises
 727        ------
 728        `aiobungie.NotFound`
 729            The requested clan was not found.
 730        """
 731        resp = await self.rest.fetch_clan_admins(clan_id)
 732
 733        return self.factory.deserialize_clan_members(resp)
 734
 735    async def fetch_groups_for_member(
 736        self,
 737        member_id: int,
 738        member_type: typedefs.IntAnd[enums.MembershipType],
 739        /,
 740        *,
 741        filter: int = 0,
 742        group_type: enums.GroupType = enums.GroupType.CLAN,
 743    ) -> collections.Sequence[clans.GroupMember]:
 744        """Fetch information about the groups that a given member has joined.
 745
 746        Parameters
 747        ----------
 748        member_id : `int`
 749            The member's id
 750        member_type : `aiobungie.MembershipType`
 751            The member's membership type.
 752
 753        Other Parameters
 754        ----------------
 755        filter : `int`
 756            Filter apply to list of joined groups. This Default to `0`
 757        group_type : `aiobungie.GroupType`
 758            The group's type.
 759            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 760
 761        Returns
 762        -------
 763        `collections.Sequence[aiobungie.crates.GroupMember]`
 764            A sequence of joined groups for the fetched member.
 765        """
 766        resp = await self.rest.fetch_groups_for_member(
 767            member_id, member_type, filter=filter, group_type=group_type
 768        )
 769
 770        return [
 771            self.factory.deserialize_group_member(group) for group in resp["results"]
 772        ]
 773
 774    async def fetch_potential_groups_for_member(
 775        self,
 776        member_id: int,
 777        member_type: typedefs.IntAnd[enums.MembershipType],
 778        /,
 779        *,
 780        filter: int = 0,
 781        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 782    ) -> collections.Sequence[clans.GroupMember]:
 783        """Fetch the potential groups for a clan member.
 784
 785        Parameters
 786        ----------
 787        member_id : `int`
 788            The member's id
 789        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 790            The member's membership type.
 791
 792        Other Parameters
 793        ----------------
 794        filter : `int`
 795            Filter apply to list of joined groups. This Default to `0`
 796        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 797            The group's type.
 798            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 799
 800        Returns
 801        -------
 802        `collections.Sequence[aiobungie.crates.GroupMember]`
 803            A sequence of joined potential groups for the fetched member.
 804        """
 805        resp = await self.rest.fetch_potential_groups_for_member(
 806            member_id, member_type, filter=filter, group_type=group_type
 807        )
 808
 809        return [
 810            self.factory.deserialize_group_member(group) for group in resp["results"]
 811        ]
 812
 813    async def fetch_clan_members(
 814        self,
 815        clan_id: int,
 816        /,
 817        *,
 818        name: typing.Optional[str] = None,
 819        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 820    ) -> iterators.Iterator[clans.ClanMember]:
 821        """Fetch Bungie clan members.
 822
 823        Parameters
 824        ----------
 825        clan_id : `int`
 826            The clans id
 827
 828        Other Parameters
 829        ----------------
 830        name : `typing.Optional[str]`
 831            If provided, Only players matching this name will be returned.
 832        type : `aiobungie.MembershipType`
 833            An optional clan member's membership type.
 834            This parameter is used to filter the returned results
 835            by the provided membership, For an example XBox memberships only,
 836            Otherwise will return all memberships.
 837
 838        Returns
 839        -------
 840        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
 841            An iterator over the bungie clan members.
 842
 843        Raises
 844        ------
 845        `aiobungie.NotFound`
 846            The clan was not found.
 847        """
 848        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 849
 850        return self.factory.deserialize_clan_members(resp)
 851
 852    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 853        """Fetch the clan banners.
 854
 855        Returns
 856        -------
 857        `collections.Sequence[aiobungie.crates.ClanBanner]`
 858            A sequence of the clan banners.
 859        """
 860        resp = await self.rest.fetch_clan_banners()
 861
 862        return self.factory.deserialize_clan_banners(resp)
 863
 864    # This method is required to be here since it deserialize the clan.
 865    async def kick_clan_member(
 866        self,
 867        access_token: str,
 868        /,
 869        group_id: int,
 870        membership_id: int,
 871        membership_type: typedefs.IntAnd[enums.MembershipType],
 872    ) -> clans.Clan:
 873        """Kick a member from the clan.
 874
 875        .. note::
 876            This request requires OAuth2: oauth2: `AdminGroups` scope.
 877
 878        Parameters
 879        ----------
 880        access_token : `str`
 881            The bearer access token associated with the bungie account.
 882        group_id: `int`
 883            The group id.
 884        membership_id : `int`
 885            The member id to kick.
 886        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 887            The member's membership type.
 888
 889        Returns
 890        -------
 891        `aiobungie.crates.clan.Clan`
 892            The clan that the member was kicked from.
 893        """
 894        resp = await self.rest.kick_clan_member(
 895            access_token,
 896            group_id=group_id,
 897            membership_id=membership_id,
 898            membership_type=membership_type,
 899        )
 900
 901        return self.factory.deserialize_clan(resp)
 902
 903    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 904        """Fetch a Bungie clan's weekly reward state.
 905
 906        Parameters
 907        ----------
 908        clan_id : `int`
 909            The clan's id.
 910
 911        Returns
 912        -------
 913        `aiobungie.crates.Milestone`
 914            A runtime status of the clan's milestone data.
 915        """
 916
 917        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 918
 919        return self.factory.deserialize_milestone(resp)
 920
 921    # * Destiny 2 Entities aka Definitions.
 922
 923    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 924        """Fetch a static inventory item entity given a its hash.
 925
 926        Parameters
 927        ----------
 928        hash: `int`
 929            Inventory item's hash.
 930
 931        Returns
 932        -------
 933        `aiobungie.crates.InventoryEntity`
 934            A bungie inventory item.
 935        """
 936        resp = await self.rest.fetch_inventory_item(hash)
 937
 938        return self.factory.deserialize_inventory_entity(resp)
 939
 940    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 941        """Fetch a Destiny objective entity given a its hash.
 942
 943        Parameters
 944        ----------
 945        hash: `int`
 946            objective's hash.
 947
 948        Returns
 949        -------
 950        `aiobungie.crates.ObjectiveEntity`
 951            An objective entity item.
 952        """
 953        resp = await self.rest.fetch_objective_entity(hash)
 954
 955        return self.factory.deserialize_objective_entity(resp)
 956
 957    async def search_entities(
 958        self, name: str, entity_type: str, *, page: int = 0
 959    ) -> iterators.Iterator[entity.SearchableEntity]:
 960        """Search for Destiny2 entities given a name and its type.
 961
 962        Parameters
 963        ----------
 964        name : `str`
 965            The name of the entity, i.e., Thunderlord, One thousand voices.
 966        entity_type : `str`
 967            The type of the entity, AKA Definition,
 968            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 969
 970        Other Parameters
 971        ----------------
 972        page : `int`
 973            An optional page to return. Default to 0.
 974
 975        Returns
 976        -------
 977        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
 978            An iterator over the found results matching the provided name.
 979        """
 980        resp = await self.rest.search_entities(name, entity_type, page=page)
 981
 982        return self.factory.deserialize_inventory_results(resp)
 983
 984    # Fireteams
 985
 986    async def fetch_fireteams(
 987        self,
 988        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 989        *,
 990        platform: typedefs.IntAnd[
 991            fireteams.FireteamPlatform
 992        ] = fireteams.FireteamPlatform.ANY,
 993        language: typing.Union[
 994            fireteams.FireteamLanguage, str
 995        ] = fireteams.FireteamLanguage.ALL,
 996        date_range: int = 0,
 997        page: int = 0,
 998        slots_filter: int = 0,
 999    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1000        """Fetch public Bungie fireteams with open slots.
1001
1002        Parameters
1003        ----------
1004        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1005            The fireteam activity type.
1006
1007        Other Parameters
1008        ----------------
1009        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1010            If this is provided. Then the results will be filtered with the given platform.
1011            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1012        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1013            A locale language to filter the used language in that fireteam.
1014            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1015        date_range : `int`
1016            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1017        page : `int`
1018            The page number. By default its `0` which returns all available activities.
1019        slots_filter : `int`
1020            Filter the returned fireteams based on available slots. Default is `0`
1021
1022        Returns
1023        -------
1024        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1025            A sequence of `aiobungie.crates.Fireteam` or `None`.
1026        """
1027
1028        resp = await self.rest.fetch_fireteams(
1029            activity_type,
1030            platform=platform,
1031            language=language,
1032            date_range=date_range,
1033            page=page,
1034            slots_filter=slots_filter,
1035        )
1036
1037        return self.factory.deserialize_fireteams(resp)
1038
1039    async def fetch_avaliable_clan_fireteams(
1040        self,
1041        access_token: str,
1042        group_id: int,
1043        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1044        *,
1045        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1046        language: typing.Union[fireteams.FireteamLanguage, str],
1047        date_range: int = 0,
1048        page: int = 0,
1049        public_only: bool = False,
1050        slots_filter: int = 0,
1051    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1052        """Fetch a clan's fireteams with open slots.
1053
1054        .. note::
1055            This method requires OAuth2: ReadGroups scope.
1056
1057        Parameters
1058        ----------
1059        access_token : `str`
1060            The bearer access token associated with the bungie account.
1061        group_id : `int`
1062            The group/clan id of the fireteam.
1063        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1064            The fireteam activity type.
1065
1066        Other Parameters
1067        ----------------
1068        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1069            If this is provided. Then the results will be filtered with the given platform.
1070            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1071        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1072            A locale language to filter the used language in that fireteam.
1073            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1074        date_range : `int`
1075            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1076        page : `int`
1077            The page number. By default its `0` which returns all available activities.
1078        public_only: `bool`
1079            If set to True, Then only public fireteams will be returned.
1080        slots_filter : `int`
1081            Filter the returned fireteams based on available slots. Default is `0`
1082
1083        Returns
1084        -------
1085        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1086            A sequence of  fireteams found in the clan.
1087            `None` will be returned if nothing was found.
1088        """
1089        resp = await self.rest.fetch_avaliable_clan_fireteams(
1090            access_token,
1091            group_id,
1092            activity_type,
1093            platform=platform,
1094            language=language,
1095            date_range=date_range,
1096            page=page,
1097            public_only=public_only,
1098            slots_filter=slots_filter,
1099        )
1100
1101        return self.factory.deserialize_fireteams(resp)
1102
1103    async def fetch_clan_fireteam(
1104        self, access_token: str, fireteam_id: int, group_id: int
1105    ) -> fireteams.AvailableFireteam:
1106        """Fetch a specific clan fireteam.
1107
1108        .. note::
1109            This method requires OAuth2: ReadGroups scope.
1110
1111        Parameters
1112        ----------
1113        access_token : `str`
1114            The bearer access token associated with the bungie account.
1115        group_id : `int`
1116            The group/clan id to fetch the fireteam from.
1117        fireteam_id : `int`
1118            The fireteam id to fetch.
1119
1120        Returns
1121        -------
1122        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1123            A sequence of available fireteams objects if exists. else `None` will be returned.
1124        """
1125        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1126
1127        return self.factory.deserialize_available_fireteams(
1128            resp, no_results=True
1129        )  # type: ignore[return-value]
1130
1131    async def fetch_my_clan_fireteams(
1132        self,
1133        access_token: str,
1134        group_id: int,
1135        *,
1136        include_closed: bool = True,
1137        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1138        language: typing.Union[fireteams.FireteamLanguage, str],
1139        filtered: bool = True,
1140        page: int = 0,
1141    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1142        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1143
1144        .. note::
1145            This method requires OAuth2: ReadGroups scope.
1146
1147        Parameters
1148        ----------
1149        access_token : str
1150            The bearer access token associated with the bungie account.
1151        group_id : int
1152            The group/clan id to fetch.
1153
1154        Other Parameters
1155        ----------------
1156        include_closed : bool
1157            If provided and set to True, It will also return closed fireteams.
1158            If provided and set to False, It will only return public fireteams. Default is True.
1159        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1160            If this is provided. Then the results will be filtered with the given platform.
1161            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1162        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1163            A locale language to filter the used language in that fireteam.
1164            Defaults to aiobungie.crates.FireteamLanguage.ALL
1165        filtered : bool
1166            If set to True, it will filter by clan. Otherwise not. Default is True.
1167        page : int
1168            The page number. By default its 0 which returns all available activities.
1169
1170        Returns
1171        -------
1172        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1173            A sequence of available fireteams objects if exists. else `None` will be returned.
1174        """
1175        resp = await self.rest.fetch_my_clan_fireteams(
1176            access_token,
1177            group_id,
1178            include_closed=include_closed,
1179            platform=platform,
1180            language=language,
1181            filtered=filtered,
1182            page=page,
1183        )
1184
1185        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1186
1187    # Friends and social.
1188
1189    async def fetch_friends(
1190        self, access_token: str, /
1191    ) -> collections.Sequence[friends.Friend]:
1192        """Fetch bungie friend list.
1193
1194        .. note::
1195            This requests OAuth2: ReadUserData scope.
1196
1197        Parameters
1198        -----------
1199        access_token : `str`
1200            The bearer access token associated with the bungie account.
1201
1202        Returns
1203        -------
1204        `collections.Sequence[aiobungie.crates.Friend]`
1205            A sequence of the friends associated with that access token.
1206        """
1207
1208        resp = await self.rest.fetch_friends(access_token)
1209
1210        return self.factory.deserialize_friends(resp)
1211
1212    async def fetch_friend_requests(
1213        self, access_token: str, /
1214    ) -> friends.FriendRequestView:
1215        """Fetch pending bungie friend requests queue.
1216
1217        .. note::
1218            This requests OAuth2: ReadUserData scope.
1219
1220        Parameters
1221        -----------
1222        access_token : `str`
1223            The bearer access token associated with the bungie account.
1224
1225        Returns
1226        -------
1227        `aiobungie.crates.FriendRequestView`
1228            A friend requests view of that associated access token.
1229        """
1230
1231        resp = await self.rest.fetch_friend_requests(access_token)
1232
1233        return self.factory.deserialize_friend_requests(resp)
1234
1235    # Applications and Developer portal.
1236
1237    async def fetch_application(self, appid: int, /) -> application.Application:
1238        """Fetch a Bungie application.
1239
1240        Parameters
1241        -----------
1242        appid: `int`
1243            The application id.
1244
1245        Returns
1246        --------
1247        `aiobungie.crates.Application`
1248            A Bungie application.
1249        """
1250        resp = await self.rest.fetch_application(appid)
1251
1252        return self.factory.deserialize_app(resp)
1253
1254    # Milestones
1255
1256    async def fetch_public_milestone_content(
1257        self, milestone_hash: int, /
1258    ) -> milestones.MilestoneContent:
1259        """Fetch the milestone content given its hash.
1260
1261        Parameters
1262        ----------
1263        milestone_hash : `int`
1264            The milestone hash.
1265
1266        Returns
1267        -------
1268        `aiobungie.crates.milestones.MilestoneContent`
1269            A milestone content object.
1270        """
1271        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1272
1273        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
Client( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4)
100    def __init__(
101        self,
102        token: str,
103        /,
104        client_secret: typing.Optional[str] = None,
105        client_id: typing.Optional[int] = None,
106        *,
107        max_retries: int = 4,
108    ) -> None:
109
110        self._rest = rest_.RESTClient(
111            token,
112            client_secret,
113            client_id,
114            max_retries=max_retries,
115        )
116
117        self._factory = factory_.Factory(self)

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: aiobungie.Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
135    def run(
136        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
137    ) -> None:
138        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
139        try:
140            if not loop.is_running():
141                loop.set_debug(debug)
142                loop.run_until_complete(future)
143
144        except Exception as exc:
145            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
146
147        except KeyboardInterrupt:
148            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
149            return

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
153    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
154        """Fetch and return a user object of the bungie net user associated with account.
155
156        .. warning::
157            This method requires OAuth2 scope and a Bearer access token.
158
159        Parameters
160        ----------
161        access_token : `str`
162            A valid Bearer access token for the authorization.
163
164        Returns
165        -------
166        `aiobungie.crates.user.User`
167            A user object includes the Destiny memberships and Bungie.net user.
168        """
169        resp = await self.rest.fetch_current_user_memberships(access_token)
170
171        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
173    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
174        """Fetch a Bungie user by their BungieNet id.
175
176        .. note::
177            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
178            for other memberships.
179
180        Parameters
181        ----------
182        id: `int`
183            The user id.
184
185        Returns
186        -------
187        `aiobungie.crates.user.BungieUser`
188            A Bungie user.
189
190        Raises
191        ------
192        `aiobungie.error.NotFound`
193            The user was not found.
194        """
195        payload = await self.rest.fetch_bungie_user(id)
196
197        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> aiobungie.Iterator[aiobungie.crates.user.SearchableDestinyUser]:
199    async def search_users(
200        self, name: str, /
201    ) -> iterators.Iterator[user.SearchableDestinyUser]:
202        """Search for players and return all players that matches the same name.
203
204        Parameters
205        ----------
206        name : `buildins.str`
207            The user name.
208
209        Returns
210        -------
211        `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]`
212            A sequence of destiny memberships.
213        """
214        payload = await self.rest.search_users(name)
215
216        return iterators.Iterator(
217            [
218                self.factory.deserialize_searched_user(user)
219                for user in payload["searchResults"]
220            ]
221        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
223    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
224        """Fetch all available user themes.
225
226        Returns
227        -------
228        `collections.Sequence[aiobungie.crates.user.UserThemes]`
229            A sequence of user themes.
230        """
231        data = await self.rest.fetch_user_themes()
232
233        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
235    async def fetch_hard_types(
236        self,
237        credential: int,
238        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
239        /,
240    ) -> user.HardLinkedMembership:
241        """Gets any hard linked membership given a credential.
242        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
243        Cross Save aware.
244
245        Parameters
246        ----------
247        credential: `int`
248            A valid SteamID64
249        type: `aiobungie.CredentialType`
250            The credential type. This must not be changed
251            Since its only credential that works "currently"
252
253        Returns
254        -------
255        `aiobungie.crates.user.HardLinkedMembership`
256            Information about the hard linked data.
257        """
258
259        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
260
261        return user.HardLinkedMembership(
262            id=int(payload["membershipId"]),
263            type=enums.MembershipType(payload["membershipType"]),
264            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
265        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
267    async def fetch_membership_from_id(
268        self,
269        id: int,
270        /,
271        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
272    ) -> user.User:
273        """Fetch Bungie user's memberships from their id.
274
275        Notes
276        -----
277        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
278        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
279        see `aiobungie.crates.user.DestinyMembership` for more details.
280        * If you only want the bungie user. Consider using `Client.fetch_user` method.
281
282        Parameters
283        ----------
284        id : `int`
285            The user's id.
286        type : `aiobungie.MembershipType`
287            The user's membership type.
288
289        Returns
290        -------
291        `aiobungie.crates.User`
292            A Bungie user with their membership types.
293
294        Raises
295        ------
296        aiobungie.NotFound
297            The requested user was not found.
298        """
299        payload = await self.rest.fetch_membership_from_id(id, type)
300
301        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
303    async def fetch_user_credentials(
304        self, access_token: str, membership_id: int, /
305    ) -> collections.Sequence[user.UserCredentials]:
306        """Fetch an array of credential types attached to the requested account.
307
308        .. note::
309            This method require OAuth2 Bearer access token.
310
311        Parameters
312        ----------
313        access_token : `str`
314            The bearer access token associated with the bungie account.
315        membership_id : `int`
316            The id of the membership to return.
317
318        Returns
319        -------
320        `collections.Sequence[aiobungie.crates.UserCredentials]`
321            A sequence of the attached user credentials.
322
323        Raises
324        ------
325        `aiobungie.Unauthorized`
326            The access token was wrong or no access token passed.
327        """
328        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
329
330        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
334    async def fetch_profile(
335        self,
336        member_id: int,
337        type: typedefs.IntAnd[enums.MembershipType],
338        components: list[enums.ComponentType],
339        auth: typing.Optional[str] = None,
340    ) -> components.Component:
341        """
342        Fetch a bungie profile passing components to the request.
343
344        Parameters
345        ----------
346        member_id: `int`
347            The member's id.
348        type: `aiobungie.MembershipType`
349            A valid membership type.
350        components : `list[aiobungie.ComponentType]`
351            List of profile components to collect and return.
352
353        Other Parameters
354        ----------------
355        auth : `typing.Optional[str]`
356            A Bearer access_token to make the request with.
357            This is optional and limited to components that only requires an Authorization token.
358
359        Returns
360        --------
361        `aiobungie.crates.Component`
362            A Destiny 2 player profile with its components.
363            Only passed components will be available if they exists. Otherwise they will be `None`
364
365        Raises
366        ------
367        `aiobungie.MembershipTypeError`
368            The provided membership type was invalid.
369        """
370        data = await self.rest.fetch_profile(member_id, type, components, auth)
371        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
373    async def fetch_linked_profiles(
374        self,
375        member_id: int,
376        member_type: typedefs.IntAnd[enums.MembershipType],
377        /,
378        *,
379        all: bool = False,
380    ) -> profile.LinkedProfile:
381        """Returns a summary information about all profiles linked to the requested member.
382
383        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
384
385        .. note::
386            It will only return linked accounts whose linkages you are allowed to view.
387
388        Parameters
389        ----------
390        member_id : `int`
391            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
392        member_type : `aiobungie.MembershipType`
393            The type for the membership whose linked Destiny account you want to return.
394
395        Other Parameters
396        ----------------
397        all : `bool`
398            If provided and set to `True`, All memberships regardless
399            of whether they're obscured by overrides will be returned,
400
401            If provided and set to `False`, Only available memberships will be returned.
402            The default for this is `False`.
403
404        Returns
405        -------
406        `aiobungie.crates.profile.LinkedProfile`
407            A linked profile object.
408        """
409        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
410
411        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
413    async def fetch_player(
414        self,
415        name: str,
416        code: int,
417        /,
418        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
419    ) -> collections.Sequence[user.DestinyMembership]:
420        """Fetch a Destiny 2 player's memberships.
421
422        Parameters
423        -----------
424        name: `str`
425            The unique Bungie player name.
426        code : `int`
427            The unique Bungie display name code.
428        type: `aiobungie.internal.enums.MembershipType`
429            The player's membership type, e,g. XBOX, STEAM, PSN
430
431        Returns
432        --------
433        `collections.Sequence[aiobungie.crates.DestinyMembership]`
434            A sequence of the found Destiny 2 player memberships.
435            An empty sequence will be returned if no one found.
436
437        Raises
438        ------
439        `aiobungie.MembershipTypeError`
440            The provided membership type was invalid.
441        """
442        resp = await self.rest.fetch_player(name, code, type)
443
444        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
446    async def fetch_character(
447        self,
448        member_id: int,
449        membership_type: typedefs.IntAnd[enums.MembershipType],
450        character_id: int,
451        components: list[enums.ComponentType],
452        auth: typing.Optional[str] = None,
453    ) -> components.CharacterComponent:
454        """Fetch a Destiny 2 character.
455
456        Parameters
457        ----------
458        member_id: `int`
459            A valid bungie member id.
460        character_id: `int`
461            The Destiny character id to retrieve.
462        membership_type: `aiobungie.internal.enums.MembershipType`
463            The member's membership type.
464        components: `list[aiobungie.ComponentType]`
465            Multiple arguments of character components to collect and return.
466
467        Other Parameters
468        ----------------
469        auth : `typing.Optional[str]`
470            A Bearer access_token to make the request with.
471            This is optional and limited to components that only requires an Authorization token.
472
473        Returns
474        -------
475        `aiobungie.crates.CharacterComponent`
476            A Bungie character component.
477
478        `aiobungie.MembershipTypeError`
479            The provided membership type was invalid.
480        """
481        resp = await self.rest.fetch_character(
482            member_id, membership_type, character_id, components, auth
483        )
484
485        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (aiobungie.MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
487    async def fetch_unique_weapon_history(
488        self,
489        membership_id: int,
490        character_id: int,
491        membership_type: typedefs.IntAnd[enums.MembershipType],
492    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
493        """Fetch details about unique weapon usage for a character. Includes all exotics.
494
495        Parameters
496        ----------
497        membership_id : `int`
498            The Destiny user membership id.
499        character_id : `int`
500            The character id to retrieve.
501        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
502            The Destiny user's membership type.
503
504        Returns
505        -------
506        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
507            A sequence of the weapon's extended values.
508        """
509        resp = await self._rest.fetch_unique_weapon_history(
510            membership_id, character_id, membership_type
511        )
512
513        return [
514            self._factory.deserialize_extended_weapon_values(weapon)
515            for weapon in resp["weapons"]
516        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], *, membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> aiobungie.Iterator[aiobungie.crates.activity.Activity]:
520    async def fetch_activities(
521        self,
522        member_id: int,
523        character_id: int,
524        mode: typedefs.IntAnd[enums.GameMode],
525        *,
526        membership_type: typedefs.IntAnd[
527            enums.MembershipType
528        ] = enums.MembershipType.ALL,
529        page: int = 0,
530        limit: int = 250,
531    ) -> iterators.Iterator[activity.Activity]:
532        """Fetch a Destiny 2 activity for the specified character id.
533
534        Parameters
535        ----------
536        member_id: `int`
537            The user id that starts with `4611`.
538        character_id: `int`
539            The id of the character to retrieve the activities for.
540        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
541            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
542
543        Other Parameters
544        ----------------
545        membership_type: `aiobungie.internal.enums.MembershipType`
546            The Member ship type, if nothing was passed than it will return all.
547        page: int
548            The page number. Default is `0`
549        limit: int
550            Limit the returned result. Default is `250`.
551
552        Returns
553        -------
554        `aiobungie.iterators.Iterator[aiobungie.crates.Activity]`
555            An iterator of the player's activities.
556
557        Raises
558        ------
559        `aiobungie.MembershipTypeError`
560            The provided membership type was invalid.
561        """
562        resp = await self.rest.fetch_activities(
563            member_id,
564            character_id,
565            mode,
566            membership_type=membership_type,
567            page=page,
568            limit=limit,
569        )
570
571        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
573    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
574        """Fetch a post activity details.
575
576        Parameters
577        ----------
578        instance_id: `int`
579            The activity instance id.
580
581        Returns
582        -------
583        `aiobungie.crates.PostActivity`
584           A post activity object.
585        """
586        resp = await self.rest.fetch_post_activity(instance_id)
587
588        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.Iterator[aiobungie.crates.activity.AggregatedActivity]:
590    async def fetch_aggregated_activity_stats(
591        self,
592        character_id: int,
593        membership_id: int,
594        membership_type: typedefs.IntAnd[enums.MembershipType],
595    ) -> iterators.Iterator[activity.AggregatedActivity]:
596        """Fetch aggregated activity stats for a character.
597
598        Parameters
599        ----------
600        character_id: `int`
601            The id of the character to retrieve the activities for.
602        membership_id: `int`
603            The id of the user that started with `4611`.
604        membership_type: `aiobungie.internal.enums.MembershipType`
605            The Member ship type.
606
607        Returns
608        -------
609        `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]`
610            An iterator of the player's activities.
611
612        Raises
613        ------
614        `aiobungie.MembershipTypeError`
615            The provided membership type was invalid.
616        """
617        resp = await self.rest.fetch_aggregated_activity_stats(
618            character_id, membership_id, membership_type
619        )
620
621        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (aiobungie.MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
625    async def fetch_clan_from_id(
626        self,
627        id: int,
628        /,
629        access_token: typing.Optional[str] = None,
630    ) -> clans.Clan:
631        """Fetch a Bungie Clan by its id.
632
633        Parameters
634        -----------
635        id: `int`
636            The clan id.
637
638        Returns
639        --------
640        `aiobungie.crates.Clan`
641            An Bungie clan.
642
643        Raises
644        ------
645        `aiobungie.NotFound`
646            The clan was not found.
647        """
648        resp = await self.rest.fetch_clan_from_id(id, access_token)
649
650        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
652    async def fetch_clan(
653        self,
654        name: str,
655        /,
656        access_token: typing.Optional[str] = None,
657        *,
658        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
659    ) -> clans.Clan:
660        """Fetch a Clan by its name.
661        This method will return the first clan found with given name.
662
663        Parameters
664        ----------
665        name: `str`
666            The clan name
667
668        Other Parameters
669        ----------------
670        access_token : `typing.Optional[str]`
671            An optional access token to make the request with.
672
673            If the token was bound to a member of the clan,
674            This field `aiobungie.crates.Clan.current_user_membership` will be available
675            and will return the membership of the user who made this request.
676        type : `aiobungie.GroupType`
677            The group type, Default is aiobungie.GroupType.CLAN.
678
679        Returns
680        -------
681        `aiobungie.crates.Clan`
682            A Bungie clan.
683
684        Raises
685        ------
686        `aiobungie.NotFound`
687            The clan was not found.
688        """
689        resp = await self.rest.fetch_clan(name, access_token, type=type)
690
691        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
693    async def fetch_clan_conversations(
694        self, clan_id: int, /
695    ) -> collections.Sequence[clans.ClanConversation]:
696        """Fetch the conversations/chat channels of the given clan id.
697
698        Parameters
699        ----------
700        clan_id : `int`
701            The clan id.
702
703        Returns
704        `collections.Sequence[aiobungie.crates.ClanConversation]`
705            A sequence of the clan chat channels.
706        """
707        resp = await self.rest.fetch_clan_conversations(clan_id)
708
709        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
711    async def fetch_clan_admins(
712        self, clan_id: int, /
713    ) -> iterators.Iterator[clans.ClanMember]:
714        """Fetch the clan founder and admins.
715
716        Parameters
717        ----------
718        clan_id : `int`
719            The clan id.
720
721        Returns
722        -------
723        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
724            An iterator over the found clan admins and founder.
725
726        Raises
727        ------
728        `aiobungie.NotFound`
729            The requested clan was not found.
730        """
731        resp = await self.rest.fetch_clan_admins(clan_id)
732
733        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: aiobungie.GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
735    async def fetch_groups_for_member(
736        self,
737        member_id: int,
738        member_type: typedefs.IntAnd[enums.MembershipType],
739        /,
740        *,
741        filter: int = 0,
742        group_type: enums.GroupType = enums.GroupType.CLAN,
743    ) -> collections.Sequence[clans.GroupMember]:
744        """Fetch information about the groups that a given member has joined.
745
746        Parameters
747        ----------
748        member_id : `int`
749            The member's id
750        member_type : `aiobungie.MembershipType`
751            The member's membership type.
752
753        Other Parameters
754        ----------------
755        filter : `int`
756            Filter apply to list of joined groups. This Default to `0`
757        group_type : `aiobungie.GroupType`
758            The group's type.
759            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
760
761        Returns
762        -------
763        `collections.Sequence[aiobungie.crates.GroupMember]`
764            A sequence of joined groups for the fetched member.
765        """
766        resp = await self.rest.fetch_groups_for_member(
767            member_id, member_type, filter=filter, group_type=group_type
768        )
769
770        return [
771            self.factory.deserialize_group_member(group) for group in resp["results"]
772        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
774    async def fetch_potential_groups_for_member(
775        self,
776        member_id: int,
777        member_type: typedefs.IntAnd[enums.MembershipType],
778        /,
779        *,
780        filter: int = 0,
781        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
782    ) -> collections.Sequence[clans.GroupMember]:
783        """Fetch the potential groups for a clan member.
784
785        Parameters
786        ----------
787        member_id : `int`
788            The member's id
789        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
790            The member's membership type.
791
792        Other Parameters
793        ----------------
794        filter : `int`
795            Filter apply to list of joined groups. This Default to `0`
796        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
797            The group's type.
798            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
799
800        Returns
801        -------
802        `collections.Sequence[aiobungie.crates.GroupMember]`
803            A sequence of joined potential groups for the fetched member.
804        """
805        resp = await self.rest.fetch_potential_groups_for_member(
806            member_id, member_type, filter=filter, group_type=group_type
807        )
808
809        return [
810            self.factory.deserialize_group_member(group) for group in resp["results"]
811        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
813    async def fetch_clan_members(
814        self,
815        clan_id: int,
816        /,
817        *,
818        name: typing.Optional[str] = None,
819        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
820    ) -> iterators.Iterator[clans.ClanMember]:
821        """Fetch Bungie clan members.
822
823        Parameters
824        ----------
825        clan_id : `int`
826            The clans id
827
828        Other Parameters
829        ----------------
830        name : `typing.Optional[str]`
831            If provided, Only players matching this name will be returned.
832        type : `aiobungie.MembershipType`
833            An optional clan member's membership type.
834            This parameter is used to filter the returned results
835            by the provided membership, For an example XBox memberships only,
836            Otherwise will return all memberships.
837
838        Returns
839        -------
840        `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]`
841            An iterator over the bungie clan members.
842
843        Raises
844        ------
845        `aiobungie.NotFound`
846            The clan was not found.
847        """
848        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
849
850        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
852    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
853        """Fetch the clan banners.
854
855        Returns
856        -------
857        `collections.Sequence[aiobungie.crates.ClanBanner]`
858            A sequence of the clan banners.
859        """
860        resp = await self.rest.fetch_clan_banners()
861
862        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.crates.clans.Clan:
865    async def kick_clan_member(
866        self,
867        access_token: str,
868        /,
869        group_id: int,
870        membership_id: int,
871        membership_type: typedefs.IntAnd[enums.MembershipType],
872    ) -> clans.Clan:
873        """Kick a member from the clan.
874
875        .. note::
876            This request requires OAuth2: oauth2: `AdminGroups` scope.
877
878        Parameters
879        ----------
880        access_token : `str`
881            The bearer access token associated with the bungie account.
882        group_id: `int`
883            The group id.
884        membership_id : `int`
885            The member id to kick.
886        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
887            The member's membership type.
888
889        Returns
890        -------
891        `aiobungie.crates.clan.Clan`
892            The clan that the member was kicked from.
893        """
894        resp = await self.rest.kick_clan_member(
895            access_token,
896            group_id=group_id,
897            membership_id=membership_id,
898            membership_type=membership_type,
899        )
900
901        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
903    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
904        """Fetch a Bungie clan's weekly reward state.
905
906        Parameters
907        ----------
908        clan_id : `int`
909            The clan's id.
910
911        Returns
912        -------
913        `aiobungie.crates.Milestone`
914            A runtime status of the clan's milestone data.
915        """
916
917        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
918
919        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
923    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
924        """Fetch a static inventory item entity given a its hash.
925
926        Parameters
927        ----------
928        hash: `int`
929            Inventory item's hash.
930
931        Returns
932        -------
933        `aiobungie.crates.InventoryEntity`
934            A bungie inventory item.
935        """
936        resp = await self.rest.fetch_inventory_item(hash)
937
938        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
940    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
941        """Fetch a Destiny objective entity given a its hash.
942
943        Parameters
944        ----------
945        hash: `int`
946            objective's hash.
947
948        Returns
949        -------
950        `aiobungie.crates.ObjectiveEntity`
951            An objective entity item.
952        """
953        resp = await self.rest.fetch_objective_entity(hash)
954
955        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> aiobungie.Iterator[aiobungie.crates.entity.SearchableEntity]:
957    async def search_entities(
958        self, name: str, entity_type: str, *, page: int = 0
959    ) -> iterators.Iterator[entity.SearchableEntity]:
960        """Search for Destiny2 entities given a name and its type.
961
962        Parameters
963        ----------
964        name : `str`
965            The name of the entity, i.e., Thunderlord, One thousand voices.
966        entity_type : `str`
967            The type of the entity, AKA Definition,
968            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
969
970        Other Parameters
971        ----------------
972        page : `int`
973            An optional page to return. Default to 0.
974
975        Returns
976        -------
977        `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]`
978            An iterator over the found results matching the provided name.
979        """
980        resp = await self.rest.search_entities(name, entity_type, page=page)
981
982        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
 986    async def fetch_fireteams(
 987        self,
 988        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
 989        *,
 990        platform: typedefs.IntAnd[
 991            fireteams.FireteamPlatform
 992        ] = fireteams.FireteamPlatform.ANY,
 993        language: typing.Union[
 994            fireteams.FireteamLanguage, str
 995        ] = fireteams.FireteamLanguage.ALL,
 996        date_range: int = 0,
 997        page: int = 0,
 998        slots_filter: int = 0,
 999    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1000        """Fetch public Bungie fireteams with open slots.
1001
1002        Parameters
1003        ----------
1004        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1005            The fireteam activity type.
1006
1007        Other Parameters
1008        ----------------
1009        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1010            If this is provided. Then the results will be filtered with the given platform.
1011            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1012        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1013            A locale language to filter the used language in that fireteam.
1014            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1015        date_range : `int`
1016            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1017        page : `int`
1018            The page number. By default its `0` which returns all available activities.
1019        slots_filter : `int`
1020            Filter the returned fireteams based on available slots. Default is `0`
1021
1022        Returns
1023        -------
1024        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1025            A sequence of `aiobungie.crates.Fireteam` or `None`.
1026        """
1027
1028        resp = await self.rest.fetch_fireteams(
1029            activity_type,
1030            platform=platform,
1031            language=language,
1032            date_range=date_range,
1033            page=page,
1034            slots_filter=slots_filter,
1035        )
1036
1037        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1039    async def fetch_avaliable_clan_fireteams(
1040        self,
1041        access_token: str,
1042        group_id: int,
1043        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1044        *,
1045        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1046        language: typing.Union[fireteams.FireteamLanguage, str],
1047        date_range: int = 0,
1048        page: int = 0,
1049        public_only: bool = False,
1050        slots_filter: int = 0,
1051    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1052        """Fetch a clan's fireteams with open slots.
1053
1054        .. note::
1055            This method requires OAuth2: ReadGroups scope.
1056
1057        Parameters
1058        ----------
1059        access_token : `str`
1060            The bearer access token associated with the bungie account.
1061        group_id : `int`
1062            The group/clan id of the fireteam.
1063        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1064            The fireteam activity type.
1065
1066        Other Parameters
1067        ----------------
1068        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1069            If this is provided. Then the results will be filtered with the given platform.
1070            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1071        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1072            A locale language to filter the used language in that fireteam.
1073            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1074        date_range : `int`
1075            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1076        page : `int`
1077            The page number. By default its `0` which returns all available activities.
1078        public_only: `bool`
1079            If set to True, Then only public fireteams will be returned.
1080        slots_filter : `int`
1081            Filter the returned fireteams based on available slots. Default is `0`
1082
1083        Returns
1084        -------
1085        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1086            A sequence of  fireteams found in the clan.
1087            `None` will be returned if nothing was found.
1088        """
1089        resp = await self.rest.fetch_avaliable_clan_fireteams(
1090            access_token,
1091            group_id,
1092            activity_type,
1093            platform=platform,
1094            language=language,
1095            date_range=date_range,
1096            page=page,
1097            public_only=public_only,
1098            slots_filter=slots_filter,
1099        )
1100
1101        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1103    async def fetch_clan_fireteam(
1104        self, access_token: str, fireteam_id: int, group_id: int
1105    ) -> fireteams.AvailableFireteam:
1106        """Fetch a specific clan fireteam.
1107
1108        .. note::
1109            This method requires OAuth2: ReadGroups scope.
1110
1111        Parameters
1112        ----------
1113        access_token : `str`
1114            The bearer access token associated with the bungie account.
1115        group_id : `int`
1116            The group/clan id to fetch the fireteam from.
1117        fireteam_id : `int`
1118            The fireteam id to fetch.
1119
1120        Returns
1121        -------
1122        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1123            A sequence of available fireteams objects if exists. else `None` will be returned.
1124        """
1125        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1126
1127        return self.factory.deserialize_available_fireteams(
1128            resp, no_results=True
1129        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1131    async def fetch_my_clan_fireteams(
1132        self,
1133        access_token: str,
1134        group_id: int,
1135        *,
1136        include_closed: bool = True,
1137        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1138        language: typing.Union[fireteams.FireteamLanguage, str],
1139        filtered: bool = True,
1140        page: int = 0,
1141    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1142        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1143
1144        .. note::
1145            This method requires OAuth2: ReadGroups scope.
1146
1147        Parameters
1148        ----------
1149        access_token : str
1150            The bearer access token associated with the bungie account.
1151        group_id : int
1152            The group/clan id to fetch.
1153
1154        Other Parameters
1155        ----------------
1156        include_closed : bool
1157            If provided and set to True, It will also return closed fireteams.
1158            If provided and set to False, It will only return public fireteams. Default is True.
1159        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1160            If this is provided. Then the results will be filtered with the given platform.
1161            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1162        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1163            A locale language to filter the used language in that fireteam.
1164            Defaults to aiobungie.crates.FireteamLanguage.ALL
1165        filtered : bool
1166            If set to True, it will filter by clan. Otherwise not. Default is True.
1167        page : int
1168            The page number. By default its 0 which returns all available activities.
1169
1170        Returns
1171        -------
1172        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1173            A sequence of available fireteams objects if exists. else `None` will be returned.
1174        """
1175        resp = await self.rest.fetch_my_clan_fireteams(
1176            access_token,
1177            group_id,
1178            include_closed=include_closed,
1179            platform=platform,
1180            language=language,
1181            filtered=filtered,
1182            page=page,
1183        )
1184
1185        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1189    async def fetch_friends(
1190        self, access_token: str, /
1191    ) -> collections.Sequence[friends.Friend]:
1192        """Fetch bungie friend list.
1193
1194        .. note::
1195            This requests OAuth2: ReadUserData scope.
1196
1197        Parameters
1198        -----------
1199        access_token : `str`
1200            The bearer access token associated with the bungie account.
1201
1202        Returns
1203        -------
1204        `collections.Sequence[aiobungie.crates.Friend]`
1205            A sequence of the friends associated with that access token.
1206        """
1207
1208        resp = await self.rest.fetch_friends(access_token)
1209
1210        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1212    async def fetch_friend_requests(
1213        self, access_token: str, /
1214    ) -> friends.FriendRequestView:
1215        """Fetch pending bungie friend requests queue.
1216
1217        .. note::
1218            This requests OAuth2: ReadUserData scope.
1219
1220        Parameters
1221        -----------
1222        access_token : `str`
1223            The bearer access token associated with the bungie account.
1224
1225        Returns
1226        -------
1227        `aiobungie.crates.FriendRequestView`
1228            A friend requests view of that associated access token.
1229        """
1230
1231        resp = await self.rest.fetch_friend_requests(access_token)
1232
1233        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1237    async def fetch_application(self, appid: int, /) -> application.Application:
1238        """Fetch a Bungie application.
1239
1240        Parameters
1241        -----------
1242        appid: `int`
1243            The application id.
1244
1245        Returns
1246        --------
1247        `aiobungie.crates.Application`
1248            A Bungie application.
1249        """
1250        resp = await self.rest.fetch_application(appid)
1251
1252        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1256    async def fetch_public_milestone_content(
1257        self, milestone_hash: int, /
1258    ) -> milestones.MilestoneContent:
1259        """Fetch the milestone content given its hash.
1260
1261        Parameters
1262        ----------
1263        milestone_hash : `int`
1264            The milestone hash.
1265
1266        Returns
1267        -------
1268        `aiobungie.crates.milestones.MilestoneContent`
1269            A milestone content object.
1270        """
1271        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1272
1273        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
779@typing.final
780class ClosedReasons(Flag):
781    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
782
783    NONE = 0
784    MATCHMAKING = 1 << 0
785    LOADING = 1 << 1
786    SOLO = 1 << 2
787    """The activity is required to be played solo."""
788    INTERNAL_REASONS = 1 << 3
789    """
790    The user can't be joined for one of a variety of internal reasons.
791    Basically, the game can't let you join at this time,
792    but for reasons that aren't under the control of this user
793    """
794    DISALLOWED_BY_GAME_STATE = 1 << 4
795    """The user's current activity/quest/other transitory game state is preventing joining."""
796    OFFLINE = 32768
797    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
358@typing.final
359class ComponentType(Enum):
360    """An Enum for Destiny 2 profile Components."""
361
362    NONE = 0
363
364    PROFILE = 100
365    PROFILE_INVENTORIES = 102
366    PROFILE_CURRENCIES = 103
367    PROFILE_PROGRESSION = 104
368    ALL_PROFILES = (
369        PROFILE,
370        PROFILE_INVENTORIES,
371        PROFILE_CURRENCIES,
372        PROFILE_PROGRESSION,
373    )
374    """All profile components."""
375
376    VENDORS = 400
377    VENDOR_SALES = 402
378    VENDOR_RECEIPTS = 101
379    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
380    """All vendor components."""
381
382    # Items
383    ITEM_INSTANCES = 300
384    ITEM_OBJECTIVES = 301
385    ITEM_PERKS = 302
386    ITEM_RENDER_DATA = 303
387    ITEM_STATS = 304
388    ITEM_SOCKETS = 305
389    ITEM_TALENT_GRINDS = 306
390    ITEM_PLUG_STATES = 308
391    ITEM_PLUG_OBJECTIVES = 309
392    ITEM_REUSABLE_PLUGS = 310
393
394    ALL_ITEMS = (
395        ITEM_PLUG_OBJECTIVES,
396        ITEM_PLUG_STATES,
397        ITEM_SOCKETS,
398        ITEM_INSTANCES,
399        ITEM_OBJECTIVES,
400        ITEM_PERKS,
401        ITEM_RENDER_DATA,
402        ITEM_STATS,
403        ITEM_TALENT_GRINDS,
404        ITEM_REUSABLE_PLUGS,
405    )
406    """All item components."""
407
408    PLATFORM_SILVER = 105
409    KIOSKS = 500
410    CURRENCY_LOOKUPS = 600
411    PRESENTATION_NODES = 700
412    COLLECTIBLES = 800
413    RECORDS = 900
414    TRANSITORY = 1000
415    METRICS = 1100
416    INVENTORIES = 102
417    STRING_VARIABLES = 1200
418    CRAFTABLES = 1300
419
420    CHARACTERS = 200
421    CHARACTER_INVENTORY = 201
422    CHARECTER_PROGRESSION = 202
423    CHARACTER_RENDER_DATA = 203
424    CHARACTER_ACTIVITIES = 204
425    CHARACTER_EQUIPMENT = 205
426
427    ALL_CHARACTERS = (
428        CHARACTERS,
429        CHARACTER_INVENTORY,
430        CHARECTER_PROGRESSION,
431        CHARACTER_RENDER_DATA,
432        CHARACTER_ACTIVITIES,
433        CHARACTER_EQUIPMENT,
434        RECORDS,
435    )
436    """All character components."""
437
438    ALL = (
439        *ALL_PROFILES,  # type: ignore
440        *ALL_CHARACTERS,  # type: ignore
441        *ALL_VENDORS,  # type: ignore
442        *ALL_ITEMS,  # type: ignore
443        RECORDS,
444        CURRENCY_LOOKUPS,
445        PRESENTATION_NODES,
446        COLLECTIBLES,
447        KIOSKS,
448        METRICS,
449        PLATFORM_SILVER,
450        INVENTORIES,
451        STRING_VARIABLES,
452        TRANSITORY,
453        CRAFTABLES,
454    )
455    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
661@typing.final
662class CredentialType(int, Enum):
663    """The types of the accounts system supports at bungie."""
664
665    NONE = 0
666    XUID = 1
667    PSNID = 2
668    WILD = 3
669    FAKE = 4
670    FACEBOOK = 5
671    GOOGLE = 8
672    WINDOWS = 9
673    DEMONID = 10
674    STEAMID = 12
675    BATTLENETID = 14
676    STADIAID = 16
677    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
539@typing.final
540class DamageType(int, Enum):
541    """Enums for Destiny Damage types"""
542
543    NONE = 0
544    KINETIC = 1
545    ARC = 2
546    SOLAR = 3
547    VOID = 4
548    RAID = 5
549    """This is a special damage type reserved for some raid activity encounters."""
550    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
64@typing.final
65class Difficulty(int, enums.Enum):
66    """An enum for activities difficulties."""
67
68    TRIVIAL = 0
69    EASY = 1
70    NORMAL = 2
71    CHALLENGING = 3
72    HARD = 4
73    BRAVE = 5
74    ALMOST_IMPOSSIBLE = 6
75    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
160@typing.final
161class Dungeon(int, Enum):
162    """An Enum for all available Dungeon/Like missions in Destiny 2."""
163
164    NORMAL_PRESAGE = 2124066889
165    """Normal Presage"""
166
167    MASTER_PRESAGE = 4212753278
168    """Master Presage"""
169
170    HARBINGER = 1738383283
171    """Harbinger"""
172
173    PROPHECY = 4148187374
174    """Prophecy"""
175
176    MASTER_POH = 785700673
177    """Master Pit of Heresy?"""
178
179    LEGEND_POH = 785700678
180    """Legend Pit of Heresy?"""
181
182    POH = 1375089621
183    """Normal Pit of Heresy."""
184
185    SHATTERED = 2032534090
186    """Shattered Throne"""
187
188    GOA_LEGEND = 4078656646
189    """Grasp of Avarice legend."""
190
191    GOA_MASTER = 3774021532
192    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
72class Enum(__enum.Enum):
73    """Builtin Python enum with extra handlings."""
74
75    @property
76    def name(self) -> str:  # type: ignore[override]
77        return self._name_
78
79    @property
80    def value(self) -> typing.Any:  # type: ignore[override]
81        return self._value_
82
83    def __str__(self) -> str:
84        return self._name_
85
86    def __repr__(self) -> str:
87        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
88
89    def __int__(self) -> int:
90        if isinstance(self.value, _ITERABLE):
91            raise TypeError(
92                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
93            )
94        return int(self.value)

Builtin Python enum with extra handlings.

name: str

The name of the Enum member.

value: Any

The value of the Enum member.

class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.UNDEFINED),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")  # noqa: W503
 130            or "",  # noqa: W503
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload.get("applicableMembershipTypes", [])
 138            ],
 139        )
 140
 141    def deserialize_destiny_memberships(
 142        self, data: typedefs.JSONArray
 143    ) -> collections.Sequence[user.DestinyMembership]:
 144        return [self.deserialize_destiny_membership(membership) for membership in data]
 145
 146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 147
 148        primary_membership_id: typing.Optional[int] = None
 149        if raw_primary_id := data.get("primaryMembershipId"):
 150            primary_membership_id = int(raw_primary_id)
 151
 152        return user.User(
 153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
 162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 163            raw_name
 164        ):
 165            name = raw_name
 166
 167        code: typing.Optional[int] = None
 168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 169            code = int(raw_code)
 170
 171        bungie_id: typing.Optional[int] = None
 172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 173            bungie_id = int(raw_bungie_id)
 174
 175        return user.SearchableDestinyUser(
 176            name=name,
 177            code=code,
 178            bungie_id=bungie_id,
 179            memberships=self.deserialize_destiny_memberships(
 180                payload["destinyMemberships"]
 181            ),
 182        )
 183
 184    def deserialize_user_credentials(
 185        self, payload: typedefs.JSONArray
 186    ) -> collections.Sequence[user.UserCredentials]:
 187        return [
 188            user.UserCredentials(
 189                type=enums.CredentialType(int(creds["credentialType"])),
 190                display_name=creds["credentialDisplayName"],
 191                is_public=creds["isPublic"],
 192                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
 193            )
 194            for creds in payload
 195        ]
 196
 197    def deserialize_user_themes(
 198        self, payload: typedefs.JSONArray
 199    ) -> collections.Sequence[user.UserThemes]:
 200        return [
 201            user.UserThemes(
 202                id=int(entry["userThemeId"]),
 203                name=entry["userThemeName"]
 204                if "userThemeName" in entry
 205                else undefined.UNDEFINED,
 206                description=entry["userThemeDescription"]
 207                if "userThemeDescription" in entry
 208                else undefined.UNDEFINED,
 209            )
 210            for entry in payload
 211        ]
 212
 213    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 214
 215        # This is kinda redundant
 216        data = payload
 217
 218        # This is always outside the details.
 219        current_user_map: typing.Optional[
 220            collections.Mapping[str, clans.ClanMember]
 221        ] = None
 222        if raw_current_user_map := payload.get("currentUserMemberMap"):
 223            current_user_map = {
 224                membership_type: self.deserialize_clan_member(membership)
 225                for membership_type, membership in raw_current_user_map.items()
 226            }
 227
 228        try:
 229            data = payload["detail"]
 230        except KeyError:
 231            pass
 232
 233        id = data["groupId"]
 234        name = data["name"]
 235        created_at = data["creationDate"]
 236        member_count = data["memberCount"]
 237        about = data["about"]
 238        motto = data["motto"]
 239        is_public = data["isPublic"]
 240        banner = assets.Image(str(data["bannerPath"]))
 241        avatar = assets.Image(str(data["avatarPath"]))
 242        tags = data["tags"]
 243        type = data["groupType"]
 244
 245        features = data["features"]
 246        features_obj = clans.ClanFeatures(
 247            max_members=features["maximumMembers"],
 248            max_membership_types=features["maximumMembershipsOfGroupType"],
 249            capabilities=features["capabilities"],
 250            membership_types=features["membershipTypes"],
 251            invite_permissions=features["invitePermissionOverride"],
 252            update_banner_permissions=features["updateBannerPermissionOverride"],
 253            update_culture_permissions=features["updateCulturePermissionOverride"],
 254            join_level=features["joinLevel"],
 255        )
 256
 257        information: typedefs.JSONObject = data["clanInfo"]
 258        progression: collections.Mapping[int, progressions.Progression] = {
 259            int(prog_hash): self.deserialize_progressions(prog)
 260            for prog_hash, prog in information["d2ClanProgressions"].items()
 261        }
 262
 263        founder: typedefs.NoneOr[clans.ClanMember] = None
 264        if raw_founder := payload.get("founder"):
 265            founder = self.deserialize_clan_member(raw_founder)
 266
 267        return clans.Clan(
 268            net=self._net,
 269            id=int(id),
 270            name=name,
 271            type=enums.GroupType(type),
 272            created_at=time.clean_date(created_at),
 273            member_count=member_count,
 274            motto=motto,
 275            about=about,
 276            is_public=is_public,
 277            banner=banner,
 278            avatar=avatar,
 279            tags=tags,
 280            features=features_obj,
 281            owner=founder,
 282            progressions=progression,
 283            call_sign=information["clanCallsign"],
 284            banner_data=information["clanBannerData"],
 285            chat_security=data["chatSecurity"],
 286            conversation_id=int(data["conversationId"]),
 287            allow_chat=data["allowChat"],
 288            theme=data["theme"],
 289            current_user_membership=current_user_map,
 290        )
 291
 292    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 293        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 294        return clans.ClanMember(
 295            net=self._net,
 296            last_seen_name=destiny_user.last_seen_name,
 297            id=destiny_user.id,
 298            name=destiny_user.name,
 299            icon=destiny_user.icon,
 300            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 301            group_id=int(data["groupId"]),
 302            joined_at=time.clean_date(data["joinDate"]),
 303            types=destiny_user.types,
 304            is_public=destiny_user.is_public,
 305            type=destiny_user.type,
 306            code=destiny_user.code,
 307            is_online=data["isOnline"],
 308            crossave_override=destiny_user.crossave_override,
 309            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 310            if "bungieNetUserInfo" in data
 311            else None,
 312            member_type=enums.ClanMemberType(int(data["memberType"])),
 313        )
 314
 315    def deserialize_clan_members(
 316        self, data: typedefs.JSONObject, /
 317    ) -> iterators.Iterator[clans.ClanMember]:
 318        return iterators.Iterator(
 319            [self.deserialize_clan_member(member) for member in data["results"]]
 320        )
 321
 322    def deserialize_group_member(
 323        self, payload: typedefs.JSONObject
 324    ) -> clans.GroupMember:
 325        member = payload["member"]
 326        return clans.GroupMember(
 327            net=self._net,
 328            join_date=time.clean_date(member["joinDate"]),
 329            group_id=int(member["groupId"]),
 330            member_type=enums.ClanMemberType(member["memberType"]),
 331            is_online=member["isOnline"],
 332            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 333            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 334            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 335            group=self.deserialize_clan(payload["group"]),
 336        )
 337
 338    def _deserialize_clan_conversation(
 339        self, payload: typedefs.JSONObject
 340    ) -> clans.ClanConversation:
 341        return clans.ClanConversation(
 342            net=self._net,
 343            id=int(payload["conversationId"]),
 344            group_id=int(payload["groupId"]),
 345            name=(
 346                payload["chatName"]
 347                if not typedefs.is_unknown(payload["chatName"])
 348                else undefined.UNDEFINED
 349            ),
 350            chat_enabled=payload["chatEnabled"],
 351            security=payload["chatSecurity"],
 352        )
 353
 354    def deserialize_clan_conversations(
 355        self, payload: typedefs.JSONArray
 356    ) -> collections.Sequence[clans.ClanConversation]:
 357        return [self._deserialize_clan_conversation(conv) for conv in payload]
 358
 359    def deserialize_app_owner(
 360        self, payload: typedefs.JSONObject
 361    ) -> application.ApplicationOwner:
 362        return application.ApplicationOwner(
 363            net=self._net,
 364            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
 365            id=int(payload["membershipId"]),
 366            type=enums.MembershipType(payload["membershipType"]),
 367            icon=assets.Image(str(payload["iconPath"])),
 368            is_public=payload["isPublic"],
 369            code=payload.get("bungieGlobalDisplayNameCode", None),
 370        )
 371
 372    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 373        return application.Application(
 374            id=int(payload["applicationId"]),
 375            name=payload["name"],
 376            link=payload["link"],
 377            status=payload["status"],
 378            redirect_url=payload.get("redirectUrl", None),
 379            created_at=time.clean_date(str(payload["creationDate"])),
 380            published_at=time.clean_date(str(payload["firstPublished"])),
 381            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 382            scope=payload.get("scope", undefined.UNDEFINED),
 383        )
 384
 385    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 386        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 387        return character.Character(
 388            net=self._net,
 389            id=int(payload["characterId"]),
 390            gender=enums.Gender(payload["genderType"]),
 391            race=enums.Race(payload["raceType"]),
 392            class_type=enums.Class(payload["classType"]),
 393            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 394            emblem_icon=assets.Image(str(payload["emblemPath"])),
 395            emblem_hash=int(payload["emblemHash"]),
 396            last_played=time.clean_date(payload["dateLastPlayed"]),
 397            total_played_time=total_time,
 398            member_id=int(payload["membershipId"]),
 399            member_type=enums.MembershipType(payload["membershipType"]),
 400            level=payload["baseCharacterLevel"],
 401            title_hash=payload.get("titleRecordHash", None),
 402            light=payload["light"],
 403            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 404        )
 405
 406    def deserialize_profile(
 407        self, payload: typedefs.JSONObject, /
 408    ) -> typing.Optional[profile.Profile]:
 409        if (raw_profile := payload.get("data")) is None:
 410            return None
 411
 412        payload = raw_profile
 413        id = int(payload["userInfo"]["membershipId"])
 414        name = payload["userInfo"]["displayName"]
 415        is_public = payload["userInfo"]["isPublic"]
 416        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 417        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 418        character_ids = [int(cid) for cid in payload["characterIds"]]
 419        power_cap = payload["currentSeasonRewardPowerCap"]
 420
 421        return profile.Profile(
 422            id=int(id),
 423            name=name,
 424            is_public=is_public,
 425            type=type,
 426            last_played=last_played,
 427            character_ids=character_ids,
 428            power_cap=power_cap,
 429            net=self._net,
 430        )
 431
 432    def deserialize_profile_item(
 433        self, payload: typedefs.JSONObject
 434    ) -> profile.ProfileItemImpl:
 435
 436        instance_id: typing.Optional[int] = None
 437        if raw_instance_id := payload.get("itemInstanceId"):
 438            instance_id = int(raw_instance_id)
 439
 440        version_number: typing.Optional[int] = None
 441        if raw_version := payload.get("versionNumber"):
 442            version_number = int(raw_version)
 443
 444        transfer_status = enums.TransferStatus(payload["transferStatus"])
 445
 446        return profile.ProfileItemImpl(
 447            net=self._net,
 448            hash=payload["itemHash"],
 449            quantity=payload["quantity"],
 450            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 451            location=enums.ItemLocation(payload["location"]),
 452            bucket=payload["bucketHash"],
 453            transfer_status=transfer_status,
 454            lockable=payload["lockable"],
 455            state=enums.ItemState(payload["state"]),
 456            dismantel_permissions=payload["dismantlePermission"],
 457            is_wrapper=payload["isWrapper"],
 458            instance_id=instance_id,
 459            version_number=version_number,
 460            ornament_id=payload.get("overrideStyleItemHash"),
 461        )
 462
 463    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 464        return records.Objective(
 465            net=self._net,
 466            hash=payload["objectiveHash"],
 467            visible=payload["visible"],
 468            complete=payload["complete"],
 469            completion_value=payload["completionValue"],
 470            progress=payload.get("progress"),
 471            destination_hash=payload.get("destinationHash"),
 472            activity_hash=payload.get("activityHash"),
 473        )
 474
 475    def deserialize_records(
 476        self,
 477        payload: typedefs.JSONObject,
 478        scores: typing.Optional[records.RecordScores] = None,
 479        **nodes: int,
 480    ) -> records.Record:
 481        objectives: typing.Optional[list[records.Objective]] = None
 482        interval_objectives: typing.Optional[list[records.Objective]] = None
 483        record_state: typedefs.IntAnd[records.RecordState]
 484
 485        record_state = records.RecordState(payload["state"])
 486
 487        if raw_objs := payload.get("objectives"):
 488            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 489
 490        if raw_interval_objs := payload.get("intervalObjectives"):
 491            interval_objectives = [
 492                self.deserialize_objectives(obj) for obj in raw_interval_objs
 493            ]
 494
 495        return records.Record(
 496            scores=scores,
 497            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
 498            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
 499            state=record_state,
 500            objectives=objectives,
 501            interval_objectives=interval_objectives,
 502            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 503            completion_times=payload.get("completedCount", None),
 504            reward_visibility=payload.get("rewardVisibilty", None),
 505        )
 506
 507    def deserialize_character_records(
 508        self,
 509        payload: typedefs.JSONObject,
 510        scores: typing.Optional[records.RecordScores] = None,
 511        record_hashes: typing.Optional[list[int]] = None,
 512    ) -> records.CharacterRecord:
 513
 514        record = self.deserialize_records(payload, scores)
 515        return records.CharacterRecord(
 516            scores=scores,
 517            categories_node_hash=record.categories_node_hash,
 518            seals_node_hash=record.seals_node_hash,
 519            state=record.state,
 520            objectives=record.objectives,
 521            interval_objectives=record.interval_objectives,
 522            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 523            completion_times=payload.get("completedCount"),
 524            reward_visibility=payload.get("rewardVisibilty"),
 525            record_hashes=record_hashes or [],
 526        )
 527
 528    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 529        return character.Dye(
 530            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 531        )
 532
 533    def deserialize_character_customization(
 534        self, payload: typedefs.JSONObject
 535    ) -> character.CustomizationOptions:
 536        return character.CustomizationOptions(
 537            personality=payload["personality"],
 538            face=payload["face"],
 539            skin_color=payload["skinColor"],
 540            lip_color=payload["lipColor"],
 541            eye_color=payload["eyeColor"],
 542            hair_colors=payload.get("hairColors", []),
 543            feature_colors=payload.get("featureColors", []),
 544            decal_color=payload["decalColor"],
 545            wear_helmet=payload["wearHelmet"],
 546            hair_index=payload["hairIndex"],
 547            feature_index=payload["featureIndex"],
 548            decal_index=payload["decalIndex"],
 549        )
 550
 551    def deserialize_character_minimal_equipments(
 552        self, payload: typedefs.JSONObject
 553    ) -> character.MinimalEquipments:
 554        dyes = None
 555        if raw_dyes := payload.get("dyes"):
 556            if raw_dyes:
 557                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 558        return character.MinimalEquipments(
 559            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 560        )
 561
 562    def deserialize_character_render_data(
 563        self, payload: typedefs.JSONObject, /
 564    ) -> character.RenderedData:
 565        return character.RenderedData(
 566            net=self._net,
 567            customization=self.deserialize_character_customization(
 568                payload["customization"]
 569            ),
 570            custom_dyes=[
 571                self.deserialize_character_dye(dye)
 572                for dye in payload["customDyes"]
 573                if dye
 574            ],
 575            equipment=[
 576                self.deserialize_character_minimal_equipments(equipment)
 577                for equipment in payload["peerView"]["equipment"]
 578            ],
 579        )
 580
 581    def deserialize_available_activity(
 582        self, payload: typedefs.JSONObject
 583    ) -> activity.AvailableActivity:
 584        return activity.AvailableActivity(
 585            hash=payload["activityHash"],
 586            is_new=payload["isNew"],
 587            is_completed=payload["isCompleted"],
 588            is_visible=payload["isVisible"],
 589            display_level=payload.get("displayLevel"),
 590            recommended_light=payload.get("recommendedLight"),
 591            difficulty=activity.Difficulty(payload["difficultyTier"]),
 592            can_join=payload["canJoin"],
 593            can_lead=payload["canLead"],
 594        )
 595
 596    def deserialize_character_activity(
 597        self, payload: typedefs.JSONObject
 598    ) -> activity.CharacterActivity:
 599        current_mode: typing.Optional[enums.GameMode] = None
 600        if raw_current_mode := payload.get("currentActivityModeType"):
 601            current_mode = enums.GameMode(raw_current_mode)
 602
 603        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 604        if raw_current_modes := payload.get("currentActivityModeTypes"):
 605            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 606
 607        return activity.CharacterActivity(
 608            date_started=time.clean_date(payload["dateActivityStarted"]),
 609            current_hash=payload["currentActivityHash"],
 610            current_mode_hash=payload["currentActivityModeHash"],
 611            current_mode=current_mode,
 612            current_mode_hashes=payload.get("currentActivityModeHashes"),
 613            current_mode_types=current_mode_types,
 614            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 615            last_story_hash=payload["lastCompletedStoryHash"],
 616            available_activities=[
 617                self.deserialize_available_activity(activity_)
 618                for activity_ in payload["availableActivities"]
 619            ],
 620        )
 621
 622    def deserialize_profile_items(
 623        self, payload: typedefs.JSONObject, /
 624    ) -> list[profile.ProfileItemImpl]:
 625        return [self.deserialize_profile_item(item) for item in payload["items"]]
 626
 627    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 628        return records.Node(
 629            state=int(payload["state"]),
 630            objective=self.deserialize_objectives(payload["objective"])
 631            if "objective" in payload
 632            else None,
 633            progress_value=int(payload["progressValue"]),
 634            completion_value=int(payload["completionValue"]),
 635            record_category_score=int(payload["recordCategoryScore"])
 636            if "recordCategoryScore" in payload
 637            else None,
 638        )
 639
 640    @staticmethod
 641    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 642        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 643        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 644            recent_collectibles = [
 645                int(item_hash) for item_hash in raw_recent_collectibles
 646            ]
 647
 648        collectibles: dict[int, int] = {}
 649        for item_hash, mapping in payload["collectibles"].items():
 650            collectibles[int(item_hash)] = int(mapping["state"])
 651
 652        return items.Collectible(
 653            recent_collectibles=recent_collectibles,
 654            collectibles=collectibles,
 655            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 656            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 657        )
 658
 659    @staticmethod
 660    def _deserialize_currencies(
 661        payload: typedefs.JSONObject,
 662    ) -> collections.Sequence[items.Currency]:
 663        return [
 664            items.Currency(hash=int(item_hash), amount=int(amount))
 665            for item_hash, amount in payload["itemQuantities"].items()
 666        ]
 667
 668    def deserialize_progressions(
 669        self, payload: typedefs.JSONObject
 670    ) -> progressions.Progression:
 671        return progressions.Progression(
 672            hash=int(payload["progressionHash"]),
 673            level=int(payload["level"]),
 674            cap=int(payload["levelCap"]),
 675            daily_limit=int(payload["dailyLimit"]),
 676            weekly_limit=int(payload["weeklyLimit"]),
 677            current_progress=int(payload["currentProgress"]),
 678            daily_progress=int(payload["dailyProgress"]),
 679            needed=int(payload["progressToNextLevel"]),
 680            next_level=int(payload["nextLevelAt"]),
 681        )
 682
 683    def _deserialize_factions(
 684        self, payload: typedefs.JSONObject
 685    ) -> progressions.Factions:
 686        progs = self.deserialize_progressions(payload)
 687        return progressions.Factions(
 688            hash=progs.hash,
 689            level=progs.level,
 690            cap=progs.cap,
 691            daily_limit=progs.daily_limit,
 692            weekly_limit=progs.weekly_limit,
 693            current_progress=progs.current_progress,
 694            daily_progress=progs.daily_progress,
 695            needed=progs.needed,
 696            next_level=progs.next_level,
 697            faction_hash=payload["factionHash"],
 698            faction_vendor_hash=payload["factionVendorIndex"],
 699        )
 700
 701    def _deserialize_milestone_available_quest(
 702        self, payload: typedefs.JSONObject
 703    ) -> milestones.MilestoneQuest:
 704        return milestones.MilestoneQuest(
 705            item_hash=payload["questItemHash"],
 706            status=self._deserialize_milestone_quest_status(payload["status"]),
 707        )
 708
 709    def _deserialize_milestone_activity(
 710        self, payload: typedefs.JSONObject
 711    ) -> milestones.MilestoneActivity:
 712
 713        phases: typing.Optional[
 714            collections.Sequence[milestones.MilestoneActivityPhase]
 715        ] = None
 716        if raw_phases := payload.get("phases"):
 717            phases = [
 718                milestones.MilestoneActivityPhase(
 719                    is_completed=obj["complete"], hash=obj["phaseHash"]
 720                )
 721                for obj in raw_phases
 722            ]
 723
 724        return milestones.MilestoneActivity(
 725            hash=payload["activityHash"],
 726            challenges=[
 727                self.deserialize_objectives(obj["objective"])
 728                for obj in payload["challenges"]
 729            ],
 730            modifier_hashes=payload.get("modifierHashes"),
 731            boolean_options=payload.get("booleanActivityOptions"),
 732            phases=phases,
 733        )
 734
 735    def _deserialize_milestone_quest_status(
 736        self, payload: typedefs.JSONObject
 737    ) -> milestones.QuestStatus:
 738        return milestones.QuestStatus(
 739            net=self._net,
 740            quest_hash=payload["questHash"],
 741            step_hash=payload["stepHash"],
 742            step_objectives=[
 743                self.deserialize_objectives(objective)
 744                for objective in payload["stepObjectives"]
 745            ],
 746            is_tracked=payload["tracked"],
 747            is_completed=payload["completed"],
 748            started=payload["started"],
 749            item_instance_id=payload["itemInstanceId"],
 750            vendor_hash=payload.get("vendorHash"),
 751            is_redeemed=payload["redeemed"],
 752        )
 753
 754    def _deserialize_milestone_rewards(
 755        self, payload: typedefs.JSONObject
 756    ) -> milestones.MilestoneReward:
 757        return milestones.MilestoneReward(
 758            category_hash=payload["rewardCategoryHash"],
 759            entries=[
 760                milestones.MilestoneRewardEntry(
 761                    entry_hash=entry["rewardEntryHash"],
 762                    is_earned=entry["earned"],
 763                    is_redeemed=entry["redeemed"],
 764                )
 765                for entry in payload["entries"]
 766            ],
 767        )
 768
 769    def deserialize_milestone(
 770        self, payload: typedefs.JSONObject
 771    ) -> milestones.Milestone:
 772        start_date: typing.Optional[datetime.datetime] = None
 773        if raw_start_date := payload.get("startDate"):
 774            start_date = time.clean_date(raw_start_date)
 775
 776        end_date: typing.Optional[datetime.datetime] = None
 777        if raw_end_date := payload.get("endDate"):
 778            end_date = time.clean_date(raw_end_date)
 779
 780        rewards: typing.Optional[
 781            collections.Collection[milestones.MilestoneReward]
 782        ] = None
 783        if raw_rewards := payload.get("rewards"):
 784            rewards = [
 785                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 786            ]
 787
 788        activities: typing.Optional[
 789            collections.Sequence[milestones.MilestoneActivity]
 790        ] = None
 791        if raw_activities := payload.get("activities"):
 792            activities = [
 793                self._deserialize_milestone_activity(active)
 794                for active in raw_activities
 795            ]
 796
 797        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 798        if raw_quests := payload.get("availableQuests"):
 799            quests = [
 800                self._deserialize_milestone_available_quest(quest)
 801                for quest in raw_quests
 802            ]
 803
 804        vendors: typing.Optional[
 805            collections.Sequence[milestones.MilestoneVendor]
 806        ] = None
 807        if raw_vendors := payload.get("vendors"):
 808            vendors = [
 809                milestones.MilestoneVendor(
 810                    vendor_hash=vendor["vendorHash"],
 811                    preview_itemhash=vendor.get("previewItemHash"),
 812                )
 813                for vendor in raw_vendors
 814            ]
 815
 816        return milestones.Milestone(
 817            hash=payload["milestoneHash"],
 818            start_date=start_date,
 819            end_date=end_date,
 820            order=payload["order"],
 821            rewards=rewards,
 822            available_quests=quests,
 823            activities=activities,
 824            vendors=vendors,
 825        )
 826
 827    def _deserialize_artifact_tiers(
 828        self, payload: typedefs.JSONObject
 829    ) -> season.ArtifactTier:
 830        return season.ArtifactTier(
 831            hash=payload["tierHash"],
 832            is_unlocked=payload["isUnlocked"],
 833            points_to_unlock=payload["pointsToUnlock"],
 834            items=[
 835                season.ArtifactTierItem(
 836                    hash=item["itemHash"], is_active=item["isActive"]
 837                )
 838                for item in payload["items"]
 839            ],
 840        )
 841
 842    def deserialize_characters(
 843        self, payload: typedefs.JSONObject
 844    ) -> collections.Mapping[int, character.Character]:
 845        return {
 846            int(char_id): self._set_character_attrs(char)
 847            for char_id, char in payload["data"].items()
 848        }
 849
 850    def deserialize_character(
 851        self, payload: typedefs.JSONObject
 852    ) -> character.Character:
 853        return self._set_character_attrs(payload)
 854
 855    def deserialize_character_equipments(
 856        self, payload: typedefs.JSONObject
 857    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 858        return {
 859            int(char_id): self.deserialize_profile_items(item)
 860            for char_id, item in payload["data"].items()
 861        }
 862
 863    def deserialize_character_activities(
 864        self, payload: typedefs.JSONObject
 865    ) -> collections.Mapping[int, activity.CharacterActivity]:
 866        return {
 867            int(char_id): self.deserialize_character_activity(data)
 868            for char_id, data in payload["data"].items()
 869        }
 870
 871    def deserialize_characters_render_data(
 872        self, payload: typedefs.JSONObject
 873    ) -> collections.Mapping[int, character.RenderedData]:
 874        return {
 875            int(char_id): self.deserialize_character_render_data(data)
 876            for char_id, data in payload["data"].items()
 877        }
 878
 879    def deserialize_character_progressions(
 880        self, payload: typedefs.JSONObject
 881    ) -> character.CharacterProgression:
 882        progressions_ = {
 883            int(prog_id): self.deserialize_progressions(prog)
 884            for prog_id, prog in payload["progressions"].items()
 885        }
 886
 887        factions = {
 888            int(faction_id): self._deserialize_factions(faction)
 889            for faction_id, faction in payload["factions"].items()
 890        }
 891
 892        milestones_ = {
 893            int(milestone_hash): self.deserialize_milestone(milestone)
 894            for milestone_hash, milestone in payload["milestones"].items()
 895        }
 896
 897        uninstanced_item_objectives = {
 898            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 899            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 900        }
 901
 902        artifact = payload["seasonalArtifact"]
 903        seasonal_artifact = season.CharacterScopedArtifact(
 904            hash=artifact["artifactHash"],
 905            points_used=artifact["pointsUsed"],
 906            reset_count=artifact["resetCount"],
 907            tiers=[
 908                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 909            ],
 910        )
 911        checklists = payload["checklists"]
 912
 913        return character.CharacterProgression(
 914            progressions=progressions_,
 915            factions=factions,
 916            checklists=checklists,
 917            milestones=milestones_,
 918            seasonal_artifact=seasonal_artifact,
 919            uninstanced_item_objectives=uninstanced_item_objectives,
 920        )
 921
 922    def deserialize_character_progressions_mapping(
 923        self, payload: typedefs.JSONObject
 924    ) -> collections.Mapping[int, character.CharacterProgression]:
 925        character_progressions: collections.Mapping[
 926            int, character.CharacterProgression
 927        ] = {}
 928        for char_id, data in payload["data"].items():
 929            # A little hack to stop mypy complaining about Mapping <-> dict
 930            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 931        return character_progressions
 932
 933    def deserialize_characters_records(
 934        self,
 935        payload: typedefs.JSONObject,
 936    ) -> collections.Mapping[int, records.CharacterRecord]:
 937
 938        return {
 939            int(rec_id): self.deserialize_character_records(
 940                rec, record_hashes=payload.get("featuredRecordHashes")
 941            )
 942            for rec_id, rec in payload["records"].items()
 943        }
 944
 945    def deserialize_profile_records(
 946        self, payload: typedefs.JSONObject
 947    ) -> collections.Mapping[int, records.Record]:
 948        raw_profile_records = payload["data"]
 949        scores = records.RecordScores(
 950            current_score=raw_profile_records["score"],
 951            legacy_score=raw_profile_records["legacyScore"],
 952            lifetime_score=raw_profile_records["lifetimeScore"],
 953        )
 954        return {
 955            int(record_id): self.deserialize_records(
 956                record,
 957                scores,
 958                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 959                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 960            )
 961            for record_id, record in raw_profile_records["records"].items()
 962        }
 963
 964    def _deserialize_craftable_socket_plug(
 965        self, payload: typedefs.JSONObject
 966    ) -> items.CraftableSocketPlug:
 967        return items.CraftableSocketPlug(
 968            item_hash=int(payload["plugItemHash"]),
 969            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 970        )
 971
 972    def _deserialize_craftable_socket(
 973        self, payload: typedefs.JSONObject
 974    ) -> items.CraftableSocket:
 975
 976        plugs: list[items.CraftableSocketPlug] = []
 977        if raw_plug := payload.get("plug"):
 978            plugs.extend(
 979                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 980            )
 981
 982        return items.CraftableSocket(
 983            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 984        )
 985
 986    def _deserialize_craftable_item(
 987        self, payload: typedefs.JSONObject
 988    ) -> items.CraftableItem:
 989
 990        return items.CraftableItem(
 991            is_visible=payload["visible"],
 992            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 993            sockets=[
 994                self._deserialize_craftable_socket(socket)
 995                for socket in payload["sockets"]
 996            ],
 997        )
 998
 999    def deserialize_craftables_component(
1000        self, payload: typedefs.JSONObject
1001    ) -> components.CraftablesComponent:
1002        return components.CraftablesComponent(
1003            net=self._net,
1004            craftables={
1005                int(item_id): self._deserialize_craftable_item(item)
1006                for item_id, item in payload["craftables"].items()
1007                if item is not None
1008            },
1009            crafting_root_node_hash=payload["craftingRootNodeHash"],
1010        )
1011
1012    def deserialize_components(  # noqa: C901 Too complex.
1013        self, payload: typedefs.JSONObject
1014    ) -> components.Component:
1015
1016        profile_: typing.Optional[profile.Profile] = None
1017        if raw_profile := payload.get("profile"):
1018            profile_ = self.deserialize_profile(raw_profile)
1019
1020        profile_progression: typing.Optional[profile.ProfileProgression] = None
1021        if raw_profile_progression := payload.get("profileProgression"):
1022            profile_progression = self.deserialize_profile_progression(
1023                raw_profile_progression
1024            )
1025
1026        profile_currencies: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_currencies := payload.get("profileCurrencies"):
1030            if "data" in raw_profile_currencies:
1031                profile_currencies = self.deserialize_profile_items(
1032                    raw_profile_currencies["data"]
1033                )
1034
1035        profile_inventories: typing.Optional[
1036            collections.Sequence[profile.ProfileItemImpl]
1037        ] = None
1038        if raw_profile_inventories := payload.get("profileInventory"):
1039            if "data" in raw_profile_inventories:
1040                profile_inventories = self.deserialize_profile_items(
1041                    raw_profile_inventories["data"]
1042                )
1043
1044        profile_records: typing.Optional[
1045            collections.Mapping[int, records.Record]
1046        ] = None
1047
1048        if raw_profile_records_ := payload.get("profileRecords"):
1049            profile_records = self.deserialize_profile_records(raw_profile_records_)
1050
1051        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1052        if raw_characters := payload.get("characters"):
1053            characters = self.deserialize_characters(raw_characters)
1054
1055        character_records: typing.Optional[
1056            collections.Mapping[int, records.CharacterRecord]
1057        ] = None
1058
1059        if raw_character_records := payload.get("characterRecords"):
1060            # Had to do it in two steps..
1061            to_update: typedefs.JSONObject = {}
1062            for _, data in raw_character_records["data"].items():
1063                for record_id, record in data.items():
1064                    to_update[record_id] = record
1065
1066            character_records = {
1067                int(rec_id): self.deserialize_character_records(
1068                    rec, record_hashes=to_update.get("featuredRecordHashes")
1069                )
1070                for rec_id, rec in to_update["records"].items()
1071            }
1072
1073        character_equipments: typing.Optional[
1074            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1075        ] = None
1076        if raw_character_equips := payload.get("characterEquipment"):
1077            character_equipments = self.deserialize_character_equipments(
1078                raw_character_equips
1079            )
1080
1081        character_inventories: typing.Optional[
1082            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1083        ] = None
1084        if raw_character_inventories := payload.get("characterInventories"):
1085            if "data" in raw_character_inventories:
1086                character_inventories = self.deserialize_character_equipments(
1087                    raw_character_inventories
1088                )
1089
1090        character_activities: typing.Optional[
1091            collections.Mapping[int, activity.CharacterActivity]
1092        ] = None
1093        if raw_char_acts := payload.get("characterActivities"):
1094            character_activities = self.deserialize_character_activities(raw_char_acts)
1095
1096        character_render_data: typing.Optional[
1097            collections.Mapping[int, character.RenderedData]
1098        ] = None
1099        if raw_character_render_data := payload.get("characterRenderData"):
1100            character_render_data = self.deserialize_characters_render_data(
1101                raw_character_render_data
1102            )
1103
1104        character_progressions: typing.Optional[
1105            collections.Mapping[int, character.CharacterProgression]
1106        ] = None
1107
1108        if raw_character_progressions := payload.get("characterProgressions"):
1109            character_progressions = self.deserialize_character_progressions_mapping(
1110                raw_character_progressions
1111            )
1112
1113        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1114        if raw_profile_string_vars := payload.get("profileStringVariables"):
1115            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1116
1117        character_string_vars: typing.Optional[
1118            collections.Mapping[int, collections.Mapping[int, int]]
1119        ] = None
1120        if raw_character_string_vars := payload.get("characterStringVariables"):
1121            character_string_vars = {
1122                int(char_id): data["integerValuesByHash"]
1123                for char_id, data in raw_character_string_vars["data"].items()
1124            }
1125
1126        metrics: typing.Optional[
1127            collections.Sequence[
1128                collections.Mapping[
1129                    int, tuple[bool, typing.Optional[records.Objective]]
1130                ]
1131            ]
1132        ] = None
1133        root_node_hash: typing.Optional[int] = None
1134
1135        if raw_metrics := payload.get("metrics"):
1136            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1137            metrics = [
1138                {
1139                    int(metrics_hash): (
1140                        data["invisible"],
1141                        self.deserialize_objectives(data["objectiveProgress"])
1142                        if "objectiveProgress" in data
1143                        else None,
1144                    )
1145                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1146                }
1147            ]
1148        transitory: typing.Optional[fireteams.FireteamParty] = None
1149        if raw_transitory := payload.get("profileTransitoryData"):
1150            if "data" in raw_transitory:
1151                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1152
1153        item_components: typing.Optional[components.ItemsComponent] = None
1154        if raw_item_components := payload.get("itemComponents"):
1155            item_components = self.deserialize_items_component(raw_item_components)
1156
1157        profile_plugsets: typing.Optional[
1158            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1159        ] = None
1160
1161        if raw_profile_plugs := payload.get("profilePlugSets"):
1162            profile_plugsets = {
1163                int(index): [self.deserialize_plug_item_state(state) for state in data]
1164                for index, data in raw_profile_plugs["data"]["plugs"].items()
1165            }
1166
1167        character_plugsets: typing.Optional[
1168            collections.Mapping[
1169                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1170            ]
1171        ] = None
1172        if raw_char_plugsets := payload.get("characterPlugSets"):
1173            character_plugsets = {
1174                int(char_id): {
1175                    int(index): [
1176                        self.deserialize_plug_item_state(state) for state in data
1177                    ]
1178                    for index, data in inner["plugs"].items()
1179                }
1180                for char_id, inner in raw_char_plugsets["data"].items()
1181            }
1182
1183        character_collectibles: typing.Optional[
1184            collections.Mapping[int, items.Collectible]
1185        ] = None
1186        if raw_character_collectibles := payload.get("characterCollectibles"):
1187            character_collectibles = {
1188                int(char_id): self._deserialize_collectible(data)
1189                for char_id, data in raw_character_collectibles["data"].items()
1190            }
1191
1192        profile_collectibles: typing.Optional[items.Collectible] = None
1193        if raw_profile_collectibles := payload.get("profileCollectibles"):
1194            profile_collectibles = self._deserialize_collectible(
1195                raw_profile_collectibles["data"]
1196            )
1197
1198        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1199        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1200            profile_nodes = {
1201                int(node_hash): self._deserialize_node(node)
1202                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1203            }
1204
1205        character_nodes: typing.Optional[
1206            collections.Mapping[int, collections.Mapping[int, records.Node]]
1207        ] = None
1208        if raw_character_nodes := payload.get("characterPresentationNodes"):
1209            character_nodes = {
1210                int(char_id): {
1211                    int(node_hash): self._deserialize_node(node)
1212                    for node_hash, node in each_character["nodes"].items()
1213                }
1214                for char_id, each_character in raw_character_nodes["data"].items()
1215            }
1216
1217        platform_silver: typing.Optional[
1218            collections.Mapping[str, profile.ProfileItemImpl]
1219        ] = None
1220        if raw_platform_silver := payload.get("platformSilver"):
1221            if "data" in raw_platform_silver:
1222                platform_silver = {
1223                    platform_name: self.deserialize_profile_item(item)
1224                    for platform_name, item in raw_platform_silver["data"][
1225                        "platformSilver"
1226                    ].items()
1227                }
1228
1229        character_currency_lookups: typing.Optional[
1230            collections.Mapping[int, collections.Sequence[items.Currency]]
1231        ] = None
1232        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1233            if "data" in raw_char_lookups:
1234                character_currency_lookups = {
1235                    int(char_id): self._deserialize_currencies(currencie)
1236                    for char_id, currencie in raw_char_lookups["data"].items()
1237                }
1238
1239        character_craftables: typing.Optional[
1240            collections.Mapping[int, components.CraftablesComponent]
1241        ] = None
1242        if raw_character_craftables := payload.get("characterCraftables"):
1243
1244            if "data" in raw_character_craftables:
1245                character_craftables = {
1246                    int(char_id): self.deserialize_craftables_component(craftable)
1247                    for char_id, craftable in raw_character_craftables["data"].items()
1248                }
1249
1250        return components.Component(
1251            profiles=profile_,
1252            profile_progression=profile_progression,
1253            profile_currencies=profile_currencies,
1254            profile_inventories=profile_inventories,
1255            profile_records=profile_records,
1256            characters=characters,
1257            character_records=character_records,
1258            character_equipments=character_equipments,
1259            character_inventories=character_inventories,
1260            character_activities=character_activities,
1261            character_render_data=character_render_data,
1262            character_progressions=character_progressions,
1263            profile_string_variables=profile_string_vars,
1264            character_string_variables=character_string_vars,
1265            metrics=metrics,
1266            root_node_hash=root_node_hash,
1267            transitory=transitory,
1268            item_components=item_components,
1269            profile_plugsets=profile_plugsets,
1270            character_plugsets=character_plugsets,
1271            character_collectibles=character_collectibles,
1272            profile_collectibles=profile_collectibles,
1273            profile_nodes=profile_nodes,
1274            character_nodes=character_nodes,
1275            platform_silver=platform_silver,
1276            character_currency_lookups=character_currency_lookups,
1277            character_craftables=character_craftables,
1278        )
1279
1280    def deserialize_items_component(
1281        self, payload: typedefs.JSONObject
1282    ) -> components.ItemsComponent:
1283        instances: typing.Optional[
1284            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1285        ] = None
1286        if raw_instances := payload.get("instances"):
1287            instances = [
1288                {
1289                    int(ins_id): self.deserialize_instanced_item(item)
1290                    for ins_id, item in raw_instances["data"].items()
1291                }
1292            ]
1293
1294        render_data: typing.Optional[
1295            collections.Mapping[int, tuple[bool, dict[int, int]]]
1296        ] = None
1297        if raw_render_data := payload.get("renderData"):
1298            render_data = {
1299                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1300                for ins_id, data in raw_render_data["data"].items()
1301            }
1302
1303        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1304        if raw_stats := payload.get("stats"):
1305            builder: collections.Mapping[int, items.ItemStatsView] = {}
1306            for ins_id, stat in raw_stats["data"].items():
1307                for _, items_ in stat.items():
1308                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1309            stats = builder
1310
1311        sockets: typing.Optional[
1312            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1313        ] = None
1314        if raw_sockets := payload.get("sockets"):
1315            sockets = {
1316                int(ins_id): [
1317                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1318                ]
1319                for ins_id, item in raw_sockets["data"].items()
1320            }
1321
1322        objeectives: typing.Optional[
1323            collections.Mapping[int, collections.Sequence[records.Objective]]
1324        ] = None
1325        if raw_objectives := payload.get("objectives"):
1326            objeectives = {
1327                int(ins_id): [self.deserialize_objectives(objective)]
1328                for ins_id, data in raw_objectives["data"].items()
1329                for objective in data["objectives"]
1330            }
1331
1332        perks: typing.Optional[
1333            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1334        ] = None
1335        if raw_perks := payload.get("perks"):
1336            perks = {
1337                int(ins_id): [
1338                    self.deserialize_item_perk(perk) for perk in item["perks"]
1339                ]
1340                for ins_id, item in raw_perks["data"].items()
1341            }
1342
1343        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1344        if raw_plug_states := payload.get("plugStates"):
1345            pending_states: list[items.PlugItemState] = []
1346            for _, plug in raw_plug_states["data"].items():
1347                pending_states.append(self.deserialize_plug_item_state(plug))
1348            plug_states = pending_states
1349
1350        reusable_plugs: typing.Optional[
1351            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1352        ] = None
1353        if raw_re_plugs := payload.get("reusablePlugs"):
1354            reusable_plugs = {
1355                int(ins_id): [
1356                    self.deserialize_plug_item_state(state) for state in inner
1357                ]
1358                for ins_id, plug in raw_re_plugs["data"].items()
1359                for inner in list(plug["plugs"].values())
1360            }
1361
1362        plug_objectives: typing.Optional[
1363            collections.Mapping[
1364                int, collections.Mapping[int, collections.Collection[records.Objective]]
1365            ]
1366        ] = None
1367        if raw_plug_objectives := payload.get("plugObjectives"):
1368            plug_objectives = {
1369                int(ins_id): {
1370                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1371                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1372                }
1373                for ins_id, inner in raw_plug_objectives["data"].items()
1374            }
1375
1376        return components.ItemsComponent(
1377            sockets=sockets,
1378            stats=stats,
1379            render_data=render_data,
1380            instances=instances,
1381            objectives=objeectives,
1382            perks=perks,
1383            plug_states=plug_states,
1384            reusable_plugs=reusable_plugs,
1385            plug_objectives=plug_objectives,
1386        )
1387
1388    def deserialize_character_component(  # type: ignore[call-arg]
1389        self, payload: typedefs.JSONObject
1390    ) -> components.CharacterComponent:
1391
1392        character_: typing.Optional[character.Character] = None
1393        if raw_singuler_character := payload.get("character"):
1394            character_ = self.deserialize_character(raw_singuler_character["data"])
1395
1396        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1397        if raw_inventory := payload.get("inventory"):
1398            if "data" in raw_inventory:
1399                inventory = self.deserialize_profile_items(raw_inventory["data"])
1400
1401        activities: typing.Optional[activity.CharacterActivity] = None
1402        if raw_activities := payload.get("activities"):
1403            activities = self.deserialize_character_activity(raw_activities["data"])
1404
1405        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1406        if raw_equipments := payload.get("equipment"):
1407            equipment = self.deserialize_profile_items(raw_equipments["data"])
1408
1409        progressions_: typing.Optional[character.CharacterProgression] = None
1410        if raw_progressions := payload.get("progressions"):
1411            progressions_ = self.deserialize_character_progressions(
1412                raw_progressions["data"]
1413            )
1414
1415        render_data: typing.Optional[character.RenderedData] = None
1416        if raw_render_data := payload.get("renderData"):
1417            render_data = self.deserialize_character_render_data(
1418                raw_render_data["data"]
1419            )
1420
1421        character_records: typing.Optional[
1422            collections.Mapping[int, records.CharacterRecord]
1423        ] = None
1424        if raw_char_records := payload.get("records"):
1425            character_records = self.deserialize_characters_records(
1426                raw_char_records["data"]
1427            )
1428
1429        item_components: typing.Optional[components.ItemsComponent] = None
1430        if raw_item_components := payload.get("itemComponents"):
1431            item_components = self.deserialize_items_component(raw_item_components)
1432
1433        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1434        if raw_nodes := payload.get("presentationNodes"):
1435            nodes = {
1436                int(node_hash): self._deserialize_node(node)
1437                for node_hash, node in raw_nodes["data"]["nodes"].items()
1438            }
1439
1440        collectibles: typing.Optional[items.Collectible] = None
1441        if raw_collectibles := payload.get("collectibles"):
1442            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1443
1444        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1445        if raw_currencies := payload.get("currencyLookups"):
1446            if "data" in raw_currencies:
1447                currency_lookups = self._deserialize_currencies(raw_currencies)
1448
1449        return components.CharacterComponent(
1450            activities=activities,
1451            equipment=equipment,
1452            inventory=inventory,
1453            progressions=progressions_,
1454            render_data=render_data,
1455            character=character_,
1456            character_records=character_records,
1457            profile_records=None,
1458            item_components=item_components,
1459            currency_lookups=currency_lookups,
1460            collectibles=collectibles,
1461            nodes=nodes,
1462        )
1463
1464    def _set_entity_attrs(
1465        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1466    ) -> entity.Entity:
1467
1468        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1469        description: undefined.UndefinedOr[str] = undefined.UNDEFINED
1470
1471        if properties := payload[key]:
1472            if (raw_name := properties["name"]) is not typedefs.Unknown:
1473                name = raw_name
1474
1475            if (
1476                raw_description := properties["description"]
1477            ) and not typedefs.is_unknown(raw_description):
1478                description = raw_description
1479
1480        return entity.Entity(
1481            net=self._net,
1482            hash=payload["hash"],
1483            index=payload["index"],
1484            name=name,
1485            description=description,
1486            has_icon=properties["hasIcon"],
1487            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1488        )
1489
1490    def deserialize_inventory_results(
1491        self, payload: typedefs.JSONObject
1492    ) -> iterators.Iterator[entity.SearchableEntity]:
1493        suggested_words: list[str] = payload["suggestedWords"]
1494
1495        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1496            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1497
1498        return iterators.Iterator(
1499            [
1500                entity.SearchableEntity(
1501                    net=self._net,
1502                    hash=data["hash"],
1503                    entity_type=data["entityType"],
1504                    weight=data["weight"],
1505                    suggested_words=suggested_words,
1506                    name=data["displayProperties"]["name"],
1507                    has_icon=data["displayProperties"]["hasIcon"],
1508                    description=_check_unknown(
1509                        data["displayProperties"]["description"]
1510                    ),
1511                    icon=assets.Image(data["displayProperties"]["icon"]),
1512                )
1513                for data in payload["results"]["results"]
1514            ]
1515        )
1516
1517    def _deserialize_inventory_item_objects(
1518        self, payload: typedefs.JSONObject
1519    ) -> entity.InventoryEntityObjects:
1520        return entity.InventoryEntityObjects(
1521            action=payload.get("action"),
1522            set_data=payload.get("setData"),
1523            stats=payload.get("stats"),
1524            equipping_block=payload.get("equippingBlock"),
1525            translation_block=payload.get("translationBlock"),
1526            preview=payload.get("preview"),
1527            quality=payload.get("quality"),
1528            value=payload.get("value"),
1529            source_data=payload.get("sourceData"),
1530            objectives=payload.get("objectives"),
1531            plug=payload.get("plug"),
1532            metrics=payload.get("metrics"),
1533            gearset=payload.get("gearset"),
1534            sack=payload.get("sack"),
1535            sockets=payload.get("sockets"),
1536            summary=payload.get("summary"),
1537            talent_gird=payload.get("talentGrid"),
1538            investments_stats=payload.get("investmentStats"),
1539            perks=payload.get("perks"),
1540            animations=payload.get("animations", []),
1541            links=payload.get("links", []),
1542        )
1543
1544    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1545        self, payload: typedefs.JSONObject, /
1546    ) -> entity.InventoryEntity:
1547
1548        props = self._set_entity_attrs(payload)
1549        objects = self._deserialize_inventory_item_objects(payload)
1550
1551        collectible_hash: typing.Optional[int] = None
1552        if raw_collectible_hash := payload.get("collectibleHash"):
1553            collectible_hash = int(raw_collectible_hash)
1554
1555        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1556        if raw_second_icon := payload.get("secondaryIcon"):
1557            secondary_icon = assets.Image(raw_second_icon)
1558
1559        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1560        if raw_second_overlay := payload.get("secondaryOverlay"):
1561            secondary_overlay = assets.Image(raw_second_overlay)
1562
1563        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1564        if raw_second_special := payload.get("secondarySpecial"):
1565            secondary_special = assets.Image(raw_second_special)
1566
1567        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1568        if raw_screenshot := payload.get("screenshot"):
1569            screenshot = assets.Image(raw_screenshot)
1570
1571        watermark_icon: typing.Optional[assets.Image] = None
1572        if raw_watermark_icon := payload.get("iconWatermark"):
1573            watermark_icon = assets.Image(raw_watermark_icon)
1574
1575        watermark_shelved: typing.Optional[assets.Image] = None
1576        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1577            watermark_shelved = assets.Image(raw_watermark_shelved)
1578
1579        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1580        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1581            raw_about
1582        ):
1583            about = raw_about
1584
1585        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1586        if (
1587            raw_ui_style := payload.get("uiItemDisplayStyle")
1588        ) and not typedefs.is_unknown(raw_ui_style):
1589            ui_item_style = raw_ui_style
1590
1591        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1592        if (
1593            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1594        ) and not typedefs.is_unknown(raw_tier_and_name):
1595            tier_and_name = raw_tier_and_name
1596
1597        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1598        if (
1599            raw_type_name := payload.get("itemTypeDisplayName")
1600        ) and not typedefs.is_unknown(raw_type_name):
1601            type_name = raw_type_name
1602
1603        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1604        if (
1605            raw_display_source := payload.get("displaySource")
1606        ) and not typedefs.is_unknown(raw_display_source):
1607            display_source = raw_display_source
1608
1609        lorehash: typing.Optional[int] = None
1610        if raw_lore_hash := payload.get("loreHash"):
1611            lorehash = int(raw_lore_hash)
1612
1613        summary_hash: typing.Optional[int] = None
1614        if raw_summary_hash := payload.get("summaryItemHash"):
1615            summary_hash = raw_summary_hash
1616
1617        breaker_type_hash: typing.Optional[int] = None
1618        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1619            breaker_type_hash = int(raw_breaker_type_hash)
1620
1621        damage_types: typing.Optional[collections.Sequence[int]] = None
1622        if raw_damage_types := payload.get("damageTypes"):
1623            damage_types = [int(type_) for type_ in raw_damage_types]
1624
1625        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1626        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1627            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1628
1629        default_damagetype_hash: typing.Optional[int] = None
1630        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1631            default_damagetype_hash = int(raw_defaultdmg_hash)
1632
1633        emblem_objective_hash: typing.Optional[int] = None
1634        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1635            emblem_objective_hash = int(raw_emblem_obj_hash)
1636
1637        tier_type: typing.Optional[enums.TierType] = None
1638        tier: typing.Optional[enums.ItemTier] = None
1639        bucket_hash: typing.Optional[int] = None
1640        recovery_hash: typing.Optional[int] = None
1641        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1642        isinstance_item: bool = False
1643        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1644        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1645        suppress_expiration: bool = False
1646        max_stack_size: typing.Optional[int] = None
1647        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1648
1649        if inventory := payload.get("inventory"):
1650            tier_type = enums.TierType(int(inventory["tierType"]))
1651            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1652            bucket_hash = int(inventory["bucketTypeHash"])
1653            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1654            tier_name = inventory["tierTypeName"]
1655            isinstance_item = inventory["isInstanceItem"]
1656            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1657            max_stack_size = int(inventory["maxStackSize"])
1658
1659            try:
1660                stack_label = inventory["stackUniqueLabel"]
1661            except KeyError:
1662                pass
1663
1664        return entity.InventoryEntity(
1665            net=self._net,
1666            collectible_hash=collectible_hash,
1667            name=props.name,
1668            about=about,
1669            emblem_objective_hash=emblem_objective_hash,
1670            suppress_expiration=suppress_expiration,
1671            max_stack_size=max_stack_size,
1672            stack_label=stack_label,
1673            tier=tier,
1674            tier_type=tier_type,
1675            tier_name=tier_name,
1676            bucket_hash=bucket_hash,
1677            recovery_bucket_hash=recovery_hash,
1678            isinstance_item=isinstance_item,
1679            expire_in_orbit_message=expire_in_orbit_message,
1680            expiration_tooltip=expire_tool_tip,
1681            lore_hash=lorehash,
1682            type_and_tier_name=tier_and_name,
1683            summary_hash=summary_hash,
1684            ui_display_style=ui_item_style,
1685            type_name=type_name,
1686            breaker_type_hash=breaker_type_hash,
1687            description=props.description,
1688            display_source=display_source,
1689            hash=props.hash,
1690            damage_types=damage_types,
1691            index=props.index,
1692            icon=props.icon,
1693            has_icon=props.has_icon,
1694            screenshot=screenshot,
1695            watermark_icon=watermark_icon,
1696            watermark_shelved=watermark_shelved,
1697            secondary_icon=secondary_icon,
1698            secondary_overlay=secondary_overlay,
1699            secondary_special=secondary_special,
1700            type=enums.ItemType(int(payload["itemType"])),
1701            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1702            trait_ids=[trait for trait in payload.get("traitIds", [])],
1703            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1704            item_class=enums.Class(int(payload["classType"])),
1705            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1706            breaker_type=int(payload["breakerType"]),
1707            default_damagetype=int(payload["defaultDamageType"]),
1708            default_damagetype_hash=default_damagetype_hash,
1709            damagetype_hashes=damagetype_hashes,
1710            tooltip_notifications=payload["tooltipNotifications"],
1711            not_transferable=payload["nonTransferrable"],
1712            allow_actions=payload["allowActions"],
1713            is_equippable=payload["equippable"],
1714            objects=objects,
1715            background_colors=payload.get("backgroundColor", {}),
1716            season_hash=payload.get("seasonHash"),
1717            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1718        )
1719
1720    def deserialize_objective_entity(
1721        self, payload: typedefs.JSONObject, /
1722    ) -> entity.ObjectiveEntity:
1723        props = self._set_entity_attrs(payload)
1724        return entity.ObjectiveEntity(
1725            net=self._net,
1726            hash=props.hash,
1727            index=props.index,
1728            description=props.description,
1729            name=props.name,
1730            has_icon=props.has_icon,
1731            icon=props.icon,
1732            unlock_value_hash=payload["unlockValueHash"],
1733            completion_value=payload["completionValue"],
1734            scope=entity.GatingScope(int(payload["scope"])),
1735            location_hash=payload["locationHash"],
1736            allowed_negative_value=payload["allowNegativeValue"],
1737            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1738            counting_downward=payload["isCountingDownward"],
1739            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1740            progress_description=payload["progressDescription"],
1741            perks=payload["perks"],
1742            stats=payload["stats"],
1743            minimum_visibility=payload["minimumVisibilityThreshold"],
1744            allow_over_completion=payload["allowOvercompletion"],
1745            show_value_style=payload["showValueOnComplete"],
1746            display_only_objective=payload["isDisplayOnlyObjective"],
1747            complete_value_style=entity.ValueUIStyle(
1748                int(payload["completedValueStyle"])
1749            ),
1750            progress_value_style=entity.ValueUIStyle(
1751                int(payload["inProgressValueStyle"])
1752            ),
1753            ui_label=payload["uiLabel"],
1754            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1755        )
1756
1757    def _deserialize_activity_values(
1758        self, payload: typedefs.JSONObject, /
1759    ) -> activity.ActivityValues:
1760        team: typing.Optional[int] = None
1761        if raw_team := payload.get("team"):
1762            team = raw_team["basic"]["value"]
1763        return activity.ActivityValues(
1764            assists=payload["assists"]["basic"]["value"],
1765            deaths=payload["deaths"]["basic"]["value"],
1766            kills=payload["kills"]["basic"]["value"],
1767            is_completed=bool(payload["completed"]["basic"]["value"]),
1768            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1769            efficiency=payload["efficiency"]["basic"]["value"],
1770            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1771            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1772            score=payload["score"]["basic"]["value"],
1773            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1774            team=team,
1775            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1776            fireteam_id=payload["fireteamId"]["basic"]["value"],
1777            start_seconds=payload["startSeconds"]["basic"]["value"],
1778            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1779            player_count=payload["playerCount"]["basic"]["value"],
1780            team_score=payload["teamScore"]["basic"]["value"],
1781        )
1782
1783    def deserialize_activity(
1784        self,
1785        payload: typedefs.JSONObject,
1786        /,
1787    ) -> activity.Activity:
1788        period = time.clean_date(payload["period"])
1789        details = payload["activityDetails"]
1790        ref_id = int(details["referenceId"])
1791        instance_id = int(details["instanceId"])
1792        mode = enums.GameMode(details["mode"])
1793        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1794        is_private = details["isPrivate"]
1795        membership_type = enums.MembershipType(int(details["membershipType"]))
1796
1797        # Since we're using the same fields for post activity method
1798        # this check is required since post activity doesn't values values
1799        values = self._deserialize_activity_values(payload["values"])
1800
1801        return activity.Activity(
1802            net=self._net,
1803            hash=ref_id,
1804            instance_id=instance_id,
1805            mode=mode,
1806            modes=modes,
1807            is_private=is_private,
1808            membership_type=membership_type,
1809            occurred_at=period,
1810            values=values,
1811        )
1812
1813    def deserialize_activities(
1814        self, payload: typedefs.JSONObject
1815    ) -> iterators.Iterator[activity.Activity]:
1816        return iterators.Iterator(
1817            [
1818                self.deserialize_activity(activity_)
1819                for activity_ in payload["activities"]
1820            ]
1821        )
1822
1823    def deserialize_extended_weapon_values(
1824        self, payload: typedefs.JSONObject
1825    ) -> activity.ExtendedWeaponValues:
1826
1827        assists: typing.Optional[int] = None
1828        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1829            assists = raw_assists["basic"]["value"]
1830        assists_damage: typing.Optional[int] = None
1831
1832        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1833            assists_damage = raw_assists_damage["basic"]["value"]
1834
1835        return activity.ExtendedWeaponValues(
1836            reference_id=int(payload["referenceId"]),
1837            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1838            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1839                "value"
1840            ],
1841            assists=assists,
1842            assists_damage=assists_damage,
1843            precision_kills_percentage=(
1844                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1845                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1846                    "displayValue"
1847                ],
1848            ),
1849        )
1850
1851    def _deserialize_extended_values(
1852        self, payload: typedefs.JSONObject
1853    ) -> activity.ExtendedValues:
1854        weapons: typing.Optional[
1855            collections.Collection[activity.ExtendedWeaponValues]
1856        ] = None
1857
1858        if raw_weapons := payload.get("weapons"):
1859            weapons = [
1860                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1861            ]
1862
1863        return activity.ExtendedValues(
1864            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1865            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1866            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1867            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1868            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1869            weapons=weapons,
1870        )
1871
1872    def deserialize_post_activity_player(
1873        self, payload: typedefs.JSONObject, /
1874    ) -> activity.PostActivityPlayer:
1875        player = payload["player"]
1876
1877        class_hash: typedefs.NoneOr[int] = None
1878        if (class_hash := player.get("classHash")) is not None:
1879            class_hash = class_hash
1880
1881        race_hash: typedefs.NoneOr[int] = None
1882        if (race_hash := player.get("raceHash")) is not None:
1883            race_hash = race_hash
1884
1885        gender_hash: typedefs.NoneOr[int] = None
1886        if (gender_hash := player.get("genderHash")) is not None:
1887            gender_hash = gender_hash
1888
1889        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1890        if (
1891            character_class := player.get("characterClass")
1892        ) and not typedefs.is_unknown(character_class):
1893            character_class = character_class
1894
1895        character_level: typedefs.NoneOr[int] = None
1896        if (character_level := player.get("characterLevel")) is not None:
1897            character_level = character_level
1898
1899        return activity.PostActivityPlayer(
1900            standing=int(payload["standing"]),
1901            score=int(payload["score"]["basic"]["value"]),
1902            character_id=payload["characterId"],
1903            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1904            character_class=character_class,
1905            character_level=character_level,
1906            race_hash=race_hash,
1907            gender_hash=gender_hash,
1908            class_hash=class_hash,
1909            light_level=int(player["lightLevel"]),
1910            emblem_hash=int(player["emblemHash"]),
1911            values=self._deserialize_activity_values(payload["values"]),
1912            extended_values=self._deserialize_extended_values(payload["extended"]),
1913        )
1914
1915    def _deserialize_post_activity_team(
1916        self, payload: typedefs.JSONObject
1917    ) -> activity.PostActivityTeam:
1918        return activity.PostActivityTeam(
1919            id=payload["teamId"],
1920            is_defeated=bool(payload["standing"]["basic"]["value"]),
1921            score=int(payload["score"]["basic"]["value"]),
1922            name=payload["teamName"],
1923        )
1924
1925    def deserialize_post_activity(
1926        self, payload: typedefs.JSONObject
1927    ) -> activity.PostActivity:
1928        period = time.clean_date(payload["period"])
1929        details = payload["activityDetails"]
1930        ref_id = int(details["referenceId"])
1931        instance_id = int(details["instanceId"])
1932        mode = enums.GameMode(details["mode"])
1933        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1934        is_private = details["isPrivate"]
1935        membership_type = enums.MembershipType(int(details["membershipType"]))
1936        return activity.PostActivity(
1937            net=self._net,
1938            hash=ref_id,
1939            membership_type=membership_type,
1940            instance_id=instance_id,
1941            mode=mode,
1942            modes=modes,
1943            is_private=is_private,
1944            occurred_at=period,
1945            starting_phase=int(payload["startingPhaseIndex"]),
1946            players=[
1947                self.deserialize_post_activity_player(player)
1948                for player in payload["entries"]
1949            ],
1950            teams=[
1951                self._deserialize_post_activity_team(team) for team in payload["teams"]
1952            ],
1953        )
1954
1955    def _deserialize_aggregated_activity_values(
1956        self, payload: typedefs.JSONObject
1957    ) -> activity.AggregatedActivityValues:
1958        # This ID is always the same for all aggregated values.
1959        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1960
1961        return activity.AggregatedActivityValues(
1962            id=activity_id,
1963            fastest_completion_time=(
1964                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1965                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1966            ),
1967            completions=int(payload["activityCompletions"]["basic"]["value"]),
1968            kills=int(payload["activityKills"]["basic"]["value"]),
1969            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1970            assists=int(payload["activityAssists"]["basic"]["value"]),
1971            seconds_played=(
1972                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1973                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1974            ),
1975            wins=int(payload["activityWins"]["basic"]["value"]),
1976            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1977            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1978            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1979            best_single_score=int(
1980                payload["activityBestSingleGameScore"]["basic"]["value"]
1981            ),
1982            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1983            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1984            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1985            kd_ratio=float(
1986                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1987            ),
1988            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1989        )
1990
1991    def deserialize_aggregated_activity(
1992        self, payload: typedefs.JSONObject
1993    ) -> activity.AggregatedActivity:
1994        return activity.AggregatedActivity(
1995            hash=int(payload["activityHash"]),
1996            values=self._deserialize_aggregated_activity_values(payload["values"]),
1997        )
1998
1999    def deserialize_aggregated_activities(
2000        self, payload: typedefs.JSONObject
2001    ) -> iterators.Iterator[activity.AggregatedActivity]:
2002        return iterators.Iterator(
2003            [
2004                self.deserialize_aggregated_activity(activity)
2005                for activity in payload["activities"]
2006            ]
2007        )
2008
2009    def deserialize_linked_profiles(
2010        self, payload: typedefs.JSONObject
2011    ) -> profile.LinkedProfile:
2012        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2013        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2014        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2015
2016        if raw_profile := payload.get("profiles"):
2017            for pfile in raw_profile:
2018                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2019
2020        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2021            for raw_error_pfile in raw_profiles_with_errors:
2022                if error_pfile := raw_error_pfile.get("infoCard"):
2023                    error_profiles_vec.append(
2024                        self.deserialize_destiny_membership(error_pfile)
2025                    )
2026
2027        return profile.LinkedProfile(
2028            net=self._net,
2029            bungie=bungie_user,
2030            profiles=profiles_vec,
2031            profiles_with_errors=error_profiles_vec,
2032        )
2033
2034    def deserialize_clan_banners(
2035        self, payload: typedefs.JSONObject
2036    ) -> collections.Sequence[clans.ClanBanner]:
2037        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2038        if banners := payload.get("clanBannerDecals"):
2039            for k, v in banners.items():
2040                banner_obj = clans.ClanBanner(
2041                    id=int(k),
2042                    foreground=assets.Image(v["foregroundPath"]),
2043                    background=assets.Image(v["backgroundPath"]),
2044                )
2045                banners_seq.append(banner_obj)
2046        return banners_seq
2047
2048    def deserialize_public_milestone_content(
2049        self, payload: typedefs.JSONObject
2050    ) -> milestones.MilestoneContent:
2051        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2052        if raw_categories := payload.get("itemCategories"):
2053            for item in raw_categories:
2054                title = undefined.UNDEFINED
2055                if raw_title := item.get("title"):
2056                    if raw_title != typedefs.Unknown:
2057                        title = raw_title
2058                if raw_hashes := item.get("itemHashes"):
2059                    hashes: collections.Sequence[int] = raw_hashes
2060
2061                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2062
2063        about = undefined.UNDEFINED
2064        if (raw_about := payload["about"]) != typedefs.Unknown:
2065            about = raw_about
2066
2067        status = undefined.UNDEFINED
2068        if (raw_status := payload["status"]) != typedefs.Unknown:
2069            status = raw_status
2070
2071        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2072        if raw_tips := payload.get("tips"):
2073            for raw_tip in raw_tips:
2074                if raw_tip == typedefs.Unknown:
2075                    raw_tip = undefined.UNDEFINED
2076                tips.append(raw_tip)
2077
2078        return milestones.MilestoneContent(
2079            about=about, status=status, tips=tips, items=items_categoris
2080        )
2081
2082    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2083        name = undefined.UNDEFINED
2084        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2085            name = raw_name
2086
2087        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2088
2089        if raw_bungie_user := payload.get("bungieNetUser"):
2090            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2091
2092        return friends.Friend(
2093            net=self._net,
2094            id=int(payload["lastSeenAsMembershipId"]),
2095            name=name,
2096            code=payload.get("bungieGlobalDisplayNameCode"),
2097            relationship=enums.Relationship(payload["relationship"]),
2098            user=bungie_user,
2099            online_status=enums.Presence(payload["onlineStatus"]),
2100            online_title=payload["onlineTitle"],
2101            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2102        )
2103
2104    def deserialize_friends(
2105        self, payload: typedefs.JSONObject
2106    ) -> collections.Sequence[friends.Friend]:
2107        mut_seq: typing.MutableSequence[friends.Friend] = []
2108        if raw_friends := payload.get("friends"):
2109            for friend in raw_friends:
2110                mut_seq.append(self.deserialize_friend(friend))
2111        return mut_seq
2112
2113    def deserialize_friend_requests(
2114        self, payload: typedefs.JSONObject
2115    ) -> friends.FriendRequestView:
2116        incoming: typing.MutableSequence[friends.Friend] = []
2117        outgoing: typing.MutableSequence[friends.Friend] = []
2118
2119        if raw_incoming_requests := payload.get("incomingRequests"):
2120            for incoming_request in raw_incoming_requests:
2121                incoming.append(self.deserialize_friend(incoming_request))
2122
2123        if raw_outgoing_requests := payload.get("outgoingRequests"):
2124            for outgoing_request in raw_outgoing_requests:
2125                outgoing.append(self.deserialize_friend(outgoing_request))
2126
2127        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2128
2129    def _set_fireteam_fields(
2130        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2131    ) -> fireteams.Fireteam:
2132        activity_type = fireteams.FireteamActivity(payload["activityType"])
2133        return fireteams.Fireteam(
2134            id=int(payload["fireteamId"]),
2135            group_id=int(payload["groupId"]),
2136            platform=fireteams.FireteamPlatform(payload["platform"]),
2137            is_immediate=payload["isImmediate"],
2138            activity_type=activity_type,
2139            owner_id=int(payload["ownerMembershipId"]),
2140            player_slot_count=payload["playerSlotCount"],
2141            available_player_slots=payload["availablePlayerSlotCount"],
2142            available_alternate_slots=payload["availableAlternateSlotCount"],
2143            title=payload["title"],
2144            date_created=time.clean_date(payload["dateCreated"]),
2145            is_public=payload["isPublic"],
2146            locale=fireteams.FireteamLanguage(payload["locale"]),
2147            is_valid=payload["isValid"],
2148            last_modified=time.clean_date(payload["datePlayerModified"]),
2149            total_results=total_results or 0,
2150        )
2151
2152    def deserialize_fireteams(
2153        self, payload: typedefs.JSONObject
2154    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2155        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2156
2157        result: list[typedefs.JSONObject]
2158        if not (result := payload["results"]):
2159            return None
2160        for elem in result:
2161            fireteams_.append(
2162                self._set_fireteam_fields(
2163                    elem, total_results=int(payload["totalResults"])
2164                )
2165            )
2166        return fireteams_
2167
2168    def deserialize_fireteam_destiny_users(
2169        self, payload: typedefs.JSONObject
2170    ) -> fireteams.FireteamUser:
2171        destiny_obj = self.deserialize_destiny_membership(payload)
2172        # We could helpers.just return a DestinyMembership object but this is
2173        # missing the fireteam display name and id fields.
2174        return fireteams.FireteamUser(
2175            net=self._net,
2176            id=destiny_obj.id,
2177            code=destiny_obj.code,
2178            icon=destiny_obj.icon,
2179            types=destiny_obj.types,
2180            type=destiny_obj.type,
2181            is_public=destiny_obj.is_public,
2182            crossave_override=destiny_obj.crossave_override,
2183            name=destiny_obj.name,
2184            last_seen_name=destiny_obj.last_seen_name,
2185            fireteam_display_name=payload["FireteamDisplayName"],
2186            fireteam_membership_id=enums.MembershipType(
2187                payload["FireteamMembershipType"]
2188            ),
2189        )
2190
2191    def deserialize_fireteam_members(
2192        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2193    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2194        members_: list[fireteams.FireteamMember] = []
2195        if members := payload.get("Members" if not alternatives else "Alternates"):
2196            for member in members:
2197                bungie_fields = self.deserialize_partial_bungie_user(member)
2198                members_fields = fireteams.FireteamMember(
2199                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2200                    has_microphone=member["hasMicrophone"],
2201                    character_id=int(member["characterId"]),
2202                    date_joined=time.clean_date(member["dateJoined"]),
2203                    last_platform_invite_date=time.clean_date(
2204                        member["lastPlatformInviteAttemptDate"]
2205                    ),
2206                    last_platform_invite_result=int(
2207                        member["lastPlatformInviteAttemptResult"]
2208                    ),
2209                    net=self._net,
2210                    name=bungie_fields.name,
2211                    id=bungie_fields.id,
2212                    icon=bungie_fields.icon,
2213                    is_public=bungie_fields.is_public,
2214                    crossave_override=bungie_fields.crossave_override,
2215                    types=bungie_fields.types,
2216                    type=bungie_fields.type,
2217                )
2218                members_.append(members_fields)
2219        else:
2220            return None
2221        return members_
2222
2223    def deserialize_available_fireteams(
2224        self,
2225        data: typedefs.JSONObject,
2226        *,
2227        no_results: bool = False,
2228    ) -> typing.Union[
2229        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2230    ]:
2231        fireteams_: list[fireteams.AvailableFireteam] = []
2232
2233        # This needs to be used outside the results
2234        # JSON key.
2235        if no_results is True:
2236            payload = data
2237
2238        if result := payload.get("results"):
2239
2240            for fireteam in result:
2241                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2242                fireteams_fields = fireteams.AvailableFireteam(
2243                    id=found_fireteams.id,
2244                    group_id=found_fireteams.group_id,
2245                    platform=found_fireteams.platform,
2246                    activity_type=found_fireteams.activity_type,
2247                    is_immediate=found_fireteams.is_immediate,
2248                    is_public=found_fireteams.is_public,
2249                    is_valid=found_fireteams.is_valid,
2250                    owner_id=found_fireteams.owner_id,
2251                    player_slot_count=found_fireteams.player_slot_count,
2252                    available_player_slots=found_fireteams.available_player_slots,
2253                    available_alternate_slots=found_fireteams.available_alternate_slots,
2254                    title=found_fireteams.title,
2255                    date_created=found_fireteams.date_created,
2256                    locale=found_fireteams.locale,
2257                    last_modified=found_fireteams.last_modified,
2258                    total_results=found_fireteams.total_results,
2259                    members=self.deserialize_fireteam_members(payload),
2260                    alternatives=self.deserialize_fireteam_members(
2261                        payload, alternatives=True
2262                    ),
2263                )
2264            fireteams_.append(fireteams_fields)
2265            if no_results:
2266                return fireteams_fields
2267        return fireteams_
2268
2269    def deserialize_fireteam_party(
2270        self, payload: typedefs.JSONObject
2271    ) -> fireteams.FireteamParty:
2272        last_destination_hash: typing.Optional[int] = None
2273        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2274            last_destination_hash = int(raw_dest_hash)
2275
2276        return fireteams.FireteamParty(
2277            members=[
2278                self._deserialize_fireteam_party_member(member)
2279                for member in payload["partyMembers"]
2280            ],
2281            activity=self._deserialize_fireteam_party_current_activity(
2282                payload["currentActivity"]
2283            ),
2284            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2285            last_destination_hash=last_destination_hash,
2286            tracking=payload["tracking"],
2287        )
2288
2289    def _deserialize_fireteam_party_member(
2290        self, payload: typedefs.JSONObject
2291    ) -> fireteams.FireteamPartyMember:
2292
2293        status = fireteams.FireteamPartyMemberState(payload["status"])
2294        displayname: undefined.UndefinedOr[str] = undefined.UNDEFINED
2295        if raw_name := payload.get("displayName"):
2296            displayname = raw_name
2297
2298        return fireteams.FireteamPartyMember(
2299            membership_id=int(payload["membershipId"]),
2300            emblem_hash=int(payload["emblemHash"]),
2301            status=status,
2302            display_name=displayname,
2303        )
2304
2305    def _deserialize_fireteam_party_current_activity(
2306        self, payload: typedefs.JSONObject
2307    ) -> fireteams.FireteamPartyCurrentActivity:
2308        start_date: typing.Optional[datetime.datetime] = None
2309        if raw_start_date := payload.get("startTime"):
2310            start_date = time.clean_date(raw_start_date)
2311
2312        end_date: typing.Optional[datetime.datetime] = None
2313        if raw_end_date := payload.get("endTime"):
2314            end_date = time.clean_date(raw_end_date)
2315        return fireteams.FireteamPartyCurrentActivity(
2316            start_time=start_date,
2317            end_time=end_date,
2318            score=float(payload["score"]),
2319            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2320            opponenst_count=int(payload["numberOfOpponents"]),
2321            player_count=int(payload["numberOfPlayers"]),
2322        )
2323
2324    def _deserialize_fireteam_party_settings(
2325        self, payload: typedefs.JSONObject
2326    ) -> fireteams.FireteamPartySettings:
2327        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2328        return fireteams.FireteamPartySettings(
2329            open_slots=int(payload["openSlots"]),
2330            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2331            closed_reasons=closed_reasons,
2332        )
2333
2334    def deserialize_seasonal_artifact(
2335        self, payload: typedefs.JSONObject
2336    ) -> season.Artifact:
2337        if raw_artifact := payload.get("seasonalArtifact"):
2338            if points := raw_artifact.get("pointProgression"):
2339                points_prog = progressions.Progression(
2340                    hash=points["progressionHash"],
2341                    level=points["level"],
2342                    cap=points["levelCap"],
2343                    daily_limit=points["dailyLimit"],
2344                    weekly_limit=points["weeklyLimit"],
2345                    current_progress=points["currentProgress"],
2346                    daily_progress=points["dailyProgress"],
2347                    needed=points["progressToNextLevel"],
2348                    next_level=points["nextLevelAt"],
2349                )
2350
2351            if bonus := raw_artifact.get("powerBonusProgression"):
2352                power_bonus_prog = progressions.Progression(
2353                    hash=bonus["progressionHash"],
2354                    level=bonus["level"],
2355                    cap=bonus["levelCap"],
2356                    daily_limit=bonus["dailyLimit"],
2357                    weekly_limit=bonus["weeklyLimit"],
2358                    current_progress=bonus["currentProgress"],
2359                    daily_progress=bonus["dailyProgress"],
2360                    needed=bonus["progressToNextLevel"],
2361                    next_level=bonus["nextLevelAt"],
2362                )
2363            artifact = season.Artifact(
2364                net=self._net,
2365                hash=raw_artifact["artifactHash"],
2366                power_bonus=raw_artifact["powerBonus"],
2367                acquired_points=raw_artifact["pointsAcquired"],
2368                bonus=power_bonus_prog,
2369                points=points_prog,
2370            )
2371        return artifact
2372
2373    def deserialize_profile_progression(
2374        self, payload: typedefs.JSONObject
2375    ) -> profile.ProfileProgression:
2376        return profile.ProfileProgression(
2377            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2378            checklist={
2379                int(check_id): checklists
2380                for check_id, checklists in payload["data"]["checklists"].items()
2381            },
2382        )
2383
2384    def deserialize_instanced_item(
2385        self, payload: typedefs.JSONObject
2386    ) -> items.ItemInstance:
2387        damage_type_hash: typing.Optional[int] = None
2388        if raw_damagetype_hash := payload.get("damageTypeHash"):
2389            damage_type_hash = int(raw_damagetype_hash)
2390
2391        required_hashes: typing.Optional[collections.Collection[int]] = None
2392        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2393            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2394
2395        breaker_type: typing.Optional[items.ItemBreakerType] = None
2396        if raw_break_type := payload.get("breakerType"):
2397            breaker_type = items.ItemBreakerType(int(raw_break_type))
2398
2399        breaker_type_hash: typing.Optional[int] = None
2400        if raw_break_type_hash := payload.get("breakerTypeHash"):
2401            breaker_type_hash = int(raw_break_type_hash)
2402
2403        energy: typing.Optional[items.ItemEnergy] = None
2404        if raw_energy := payload.get("energy"):
2405            energy = self.deserialize_item_energy(raw_energy)
2406
2407        primary_stats = None
2408        if raw_primary_stats := payload.get("primaryStat"):
2409            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2410
2411        return items.ItemInstance(
2412            damage_type=enums.DamageType(int(payload["damageType"])),
2413            damage_type_hash=damage_type_hash,
2414            primary_stat=primary_stats,
2415            item_level=int(payload["itemLevel"]),
2416            quality=int(payload["quality"]),
2417            is_equipped=payload["isEquipped"],
2418            can_equip=payload["canEquip"],
2419            equip_required_level=int(payload["equipRequiredLevel"]),
2420            required_equip_unlock_hashes=required_hashes,
2421            cant_equip_reason=int(payload["cannotEquipReason"]),
2422            breaker_type=breaker_type,
2423            breaker_type_hash=breaker_type_hash,
2424            energy=energy,
2425        )
2426
2427    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2428        energy_hash: typing.Optional[int] = None
2429        if raw_energy_hash := payload.get("energyTypeHash"):
2430            energy_hash = int(raw_energy_hash)
2431
2432        return items.ItemEnergy(
2433            hash=energy_hash,
2434            type=items.ItemEnergyType(int(payload["energyType"])),
2435            capacity=int(payload["energyCapacity"]),
2436            used_energy=int(payload["energyUsed"]),
2437            unused_energy=int(payload["energyUnused"]),
2438        )
2439
2440    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2441        perk_hash: typing.Optional[int] = None
2442        if raw_perk_hash := payload.get("perkHash"):
2443            perk_hash = int(raw_perk_hash)
2444
2445        return items.ItemPerk(
2446            hash=perk_hash,
2447            icon=assets.Image(payload["iconPath"]),
2448            is_active=payload["isActive"],
2449            is_visible=payload["visible"],
2450        )
2451
2452    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2453        plug_hash: typing.Optional[int] = None
2454        if raw_plug_hash := payload.get("plugHash"):
2455            plug_hash = int(raw_plug_hash)
2456
2457        enable_fail_indexes: typing.Optional[list[int]] = None
2458        if raw_indexes := payload.get("enableFailIndexes"):
2459            enable_fail_indexes = [int(index) for index in raw_indexes]
2460
2461        return items.ItemSocket(
2462            plug_hash=plug_hash,
2463            is_enabled=payload["isEnabled"],
2464            enable_fail_indexes=enable_fail_indexes,
2465            is_visible=payload.get("visible"),
2466        )
2467
2468    def deserialize_item_stats_view(
2469        self, payload: typedefs.JSONObject
2470    ) -> items.ItemStatsView:
2471        return items.ItemStatsView(
2472            stat_hash=payload.get("statHash"), value=payload.get("value")
2473        )
2474
2475    def deserialize_plug_item_state(
2476        self, payload: typedefs.JSONObject
2477    ) -> items.PlugItemState:
2478        item_hash: typing.Optional[int] = None
2479        if raw_item_hash := payload.get("plugItemHash"):
2480            item_hash = int(raw_item_hash)
2481
2482        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2483        if raw_fail_indexes := payload.get("insertFailIndexes"):
2484            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2485
2486        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2487        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2488            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2489
2490        return items.PlugItemState(
2491            item_hash=item_hash,
2492            insert_fail_indexes=insert_fail_indexes,
2493            enable_fail_indexes=enable_fail_indexes,
2494            is_enabled=payload["enabled"],
2495            can_insert=payload["canInsert"],
2496        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.UNDEFINED),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")  # noqa: W503
130            or "",  # noqa: W503
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload.get("applicableMembershipTypes", [])
138            ],
139        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
141    def deserialize_destiny_memberships(
142        self, data: typedefs.JSONArray
143    ) -> collections.Sequence[user.DestinyMembership]:
144        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
147
148        primary_membership_id: typing.Optional[int] = None
149        if raw_primary_id := data.get("primaryMembershipId"):
150            primary_membership_id = int(raw_primary_id)
151
152        return user.User(
153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        name: undefined.UndefinedOr[str] = undefined.UNDEFINED
162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
163            raw_name
164        ):
165            name = raw_name
166
167        code: typing.Optional[int] = None
168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
169            code = int(raw_code)
170
171        bungie_id: typing.Optional[int] = None
172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
173            bungie_id = int(raw_bungie_id)
174
175        return user.SearchableDestinyUser(
176            name=name,
177            code=code,
178            bungie_id=bungie_id,
179            memberships=self.deserialize_destiny_memberships(
180                payload["destinyMemberships"]
181            ),
182        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
184    def deserialize_user_credentials(
185        self, payload: typedefs.JSONArray
186    ) -> collections.Sequence[user.UserCredentials]:
187        return [
188            user.UserCredentials(
189                type=enums.CredentialType(int(creds["credentialType"])),
190                display_name=creds["credentialDisplayName"],
191                is_public=creds["isPublic"],
192                self_as_string=creds.get("credentialAsString", undefined.UNDEFINED),
193            )
194            for creds in payload
195        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
197    def deserialize_user_themes(
198        self, payload: typedefs.JSONArray
199    ) -> collections.Sequence[user.UserThemes]:
200        return [
201            user.UserThemes(
202                id=int(entry["userThemeId"]),
203                name=entry["userThemeName"]
204                if "userThemeName" in entry
205                else undefined.UNDEFINED,
206                description=entry["userThemeDescription"]
207                if "userThemeDescription" in entry
208                else undefined.UNDEFINED,
209            )
210            for entry in payload
211        ]

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
213    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
214
215        # This is kinda redundant
216        data = payload
217
218        # This is always outside the details.
219        current_user_map: typing.Optional[
220            collections.Mapping[str, clans.ClanMember]
221        ] = None
222        if raw_current_user_map := payload.get("currentUserMemberMap"):
223            current_user_map = {
224                membership_type: self.deserialize_clan_member(membership)
225                for membership_type, membership in raw_current_user_map.items()
226            }
227
228        try:
229            data = payload["detail"]
230        except KeyError:
231            pass
232
233        id = data["groupId"]
234        name = data["name"]
235        created_at = data["creationDate"]
236        member_count = data["memberCount"]
237        about = data["about"]
238        motto = data["motto"]
239        is_public = data["isPublic"]
240        banner = assets.Image(str(data["bannerPath"]))
241        avatar = assets.Image(str(data["avatarPath"]))
242        tags = data["tags"]
243        type = data["groupType"]
244
245        features = data["features"]
246        features_obj = clans.ClanFeatures(
247            max_members=features["maximumMembers"],
248            max_membership_types=features["maximumMembershipsOfGroupType"],
249            capabilities=features["capabilities"],
250            membership_types=features["membershipTypes"],
251            invite_permissions=features["invitePermissionOverride"],
252            update_banner_permissions=features["updateBannerPermissionOverride"],
253            update_culture_permissions=features["updateCulturePermissionOverride"],
254            join_level=features["joinLevel"],
255        )
256
257        information: typedefs.JSONObject = data["clanInfo"]
258        progression: collections.Mapping[int, progressions.Progression] = {
259            int(prog_hash): self.deserialize_progressions(prog)
260            for prog_hash, prog in information["d2ClanProgressions"].items()
261        }
262
263        founder: typedefs.NoneOr[clans.ClanMember] = None
264        if raw_founder := payload.get("founder"):
265            founder = self.deserialize_clan_member(raw_founder)
266
267        return clans.Clan(
268            net=self._net,
269            id=int(id),
270            name=name,
271            type=enums.GroupType(type),
272            created_at=time.clean_date(created_at),
273            member_count=member_count,
274            motto=motto,
275            about=about,
276            is_public=is_public,
277            banner=banner,
278            avatar=avatar,
279            tags=tags,
280            features=features_obj,
281            owner=founder,
282            progressions=progression,
283            call_sign=information["clanCallsign"],
284            banner_data=information["clanBannerData"],
285            chat_security=data["chatSecurity"],
286            conversation_id=int(data["conversationId"]),
287            allow_chat=data["allowChat"],
288            theme=data["theme"],
289            current_user_membership=current_user_map,
290        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
292    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
293        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
294        return clans.ClanMember(
295            net=self._net,
296            last_seen_name=destiny_user.last_seen_name,
297            id=destiny_user.id,
298            name=destiny_user.name,
299            icon=destiny_user.icon,
300            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
301            group_id=int(data["groupId"]),
302            joined_at=time.clean_date(data["joinDate"]),
303            types=destiny_user.types,
304            is_public=destiny_user.is_public,
305            type=destiny_user.type,
306            code=destiny_user.code,
307            is_online=data["isOnline"],
308            crossave_override=destiny_user.crossave_override,
309            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
310            if "bungieNetUserInfo" in data
311            else None,
312            member_type=enums.ClanMemberType(int(data["memberType"])),
313        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> aiobungie.Iterator[aiobungie.crates.clans.ClanMember]:
315    def deserialize_clan_members(
316        self, data: typedefs.JSONObject, /
317    ) -> iterators.Iterator[clans.ClanMember]:
318        return iterators.Iterator(
319            [self.deserialize_clan_member(member) for member in data["results"]]
320        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
322    def deserialize_group_member(
323        self, payload: typedefs.JSONObject
324    ) -> clans.GroupMember:
325        member = payload["member"]
326        return clans.GroupMember(
327            net=self._net,
328            join_date=time.clean_date(member["joinDate"]),
329            group_id=int(member["groupId"]),
330            member_type=enums.ClanMemberType(member["memberType"]),
331            is_online=member["isOnline"],
332            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
333            inactive_memberships=payload.get("areAllMembershipsInactive", None),
334            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
335            group=self.deserialize_clan(payload["group"]),
336        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
354    def deserialize_clan_conversations(
355        self, payload: typedefs.JSONArray
356    ) -> collections.Sequence[clans.ClanConversation]:
357        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
359    def deserialize_app_owner(
360        self, payload: typedefs.JSONObject
361    ) -> application.ApplicationOwner:
362        return application.ApplicationOwner(
363            net=self._net,
364            name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED),
365            id=int(payload["membershipId"]),
366            type=enums.MembershipType(payload["membershipType"]),
367            icon=assets.Image(str(payload["iconPath"])),
368            is_public=payload["isPublic"],
369            code=payload.get("bungieGlobalDisplayNameCode", None),
370        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
372    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
373        return application.Application(
374            id=int(payload["applicationId"]),
375            name=payload["name"],
376            link=payload["link"],
377            status=payload["status"],
378            redirect_url=payload.get("redirectUrl", None),
379            created_at=time.clean_date(str(payload["creationDate"])),
380            published_at=time.clean_date(str(payload["firstPublished"])),
381            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
382            scope=payload.get("scope", undefined.UNDEFINED),
383        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
406    def deserialize_profile(
407        self, payload: typedefs.JSONObject, /
408    ) -> typing.Optional[profile.Profile]:
409        if (raw_profile := payload.get("data")) is None:
410            return None
411
412        payload = raw_profile
413        id = int(payload["userInfo"]["membershipId"])
414        name = payload["userInfo"]["displayName"]
415        is_public = payload["userInfo"]["isPublic"]
416        type = enums.MembershipType(payload["userInfo"]["membershipType"])
417        last_played = time.clean_date(str(payload["dateLastPlayed"]))
418        character_ids = [int(cid) for cid in payload["characterIds"]]
419        power_cap = payload["currentSeasonRewardPowerCap"]
420
421        return profile.Profile(
422            id=int(id),
423            name=name,
424            is_public=is_public,
425            type=type,
426            last_played=last_played,
427            character_ids=character_ids,
428            power_cap=power_cap,
429            net=self._net,
430        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
432    def deserialize_profile_item(
433        self, payload: typedefs.JSONObject
434    ) -> profile.ProfileItemImpl:
435
436        instance_id: typing.Optional[int] = None
437        if raw_instance_id := payload.get("itemInstanceId"):
438            instance_id = int(raw_instance_id)
439
440        version_number: typing.Optional[int] = None
441        if raw_version := payload.get("versionNumber"):
442            version_number = int(raw_version)
443
444        transfer_status = enums.TransferStatus(payload["transferStatus"])
445
446        return profile.ProfileItemImpl(
447            net=self._net,
448            hash=payload["itemHash"],
449            quantity=payload["quantity"],
450            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
451            location=enums.ItemLocation(payload["location"]),
452            bucket=payload["bucketHash"],
453            transfer_status=transfer_status,
454            lockable=payload["lockable"],
455            state=enums.ItemState(payload["state"]),
456            dismantel_permissions=payload["dismantlePermission"],
457            is_wrapper=payload["isWrapper"],
458            instance_id=instance_id,
459            version_number=version_number,
460            ornament_id=payload.get("overrideStyleItemHash"),
461        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
463    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
464        return records.Objective(
465            net=self._net,
466            hash=payload["objectiveHash"],
467            visible=payload["visible"],
468            complete=payload["complete"],
469            completion_value=payload["completionValue"],
470            progress=payload.get("progress"),
471            destination_hash=payload.get("destinationHash"),
472            activity_hash=payload.get("activityHash"),
473        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
475    def deserialize_records(
476        self,
477        payload: typedefs.JSONObject,
478        scores: typing.Optional[records.RecordScores] = None,
479        **nodes: int,
480    ) -> records.Record:
481        objectives: typing.Optional[list[records.Objective]] = None
482        interval_objectives: typing.Optional[list[records.Objective]] = None
483        record_state: typedefs.IntAnd[records.RecordState]
484
485        record_state = records.RecordState(payload["state"])
486
487        if raw_objs := payload.get("objectives"):
488            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
489
490        if raw_interval_objs := payload.get("intervalObjectives"):
491            interval_objectives = [
492                self.deserialize_objectives(obj) for obj in raw_interval_objs
493            ]
494
495        return records.Record(
496            scores=scores,
497            categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED),
498            seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED),
499            state=record_state,
500            objectives=objectives,
501            interval_objectives=interval_objectives,
502            redeemed_count=payload.get("intervalsRedeemedCount", 0),
503            completion_times=payload.get("completedCount", None),
504            reward_visibility=payload.get("rewardVisibilty", None),
505        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
507    def deserialize_character_records(
508        self,
509        payload: typedefs.JSONObject,
510        scores: typing.Optional[records.RecordScores] = None,
511        record_hashes: typing.Optional[list[int]] = None,
512    ) -> records.CharacterRecord:
513
514        record = self.deserialize_records(payload, scores)
515        return records.CharacterRecord(
516            scores=scores,
517            categories_node_hash=record.categories_node_hash,
518            seals_node_hash=record.seals_node_hash,
519            state=record.state,
520            objectives=record.objectives,
521            interval_objectives=record.interval_objectives,
522            redeemed_count=payload.get("intervalsRedeemedCount", 0),
523            completion_times=payload.get("completedCount"),
524            reward_visibility=payload.get("rewardVisibilty"),
525            record_hashes=record_hashes or [],
526        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
528    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
529        return character.Dye(
530            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
531        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
533    def deserialize_character_customization(
534        self, payload: typedefs.JSONObject
535    ) -> character.CustomizationOptions:
536        return character.CustomizationOptions(
537            personality=payload["personality"],
538            face=payload["face"],
539            skin_color=payload["skinColor"],
540            lip_color=payload["lipColor"],
541            eye_color=payload["eyeColor"],
542            hair_colors=payload.get("hairColors", []),
543            feature_colors=payload.get("featureColors", []),
544            decal_color=payload["decalColor"],
545            wear_helmet=payload["wearHelmet"],
546            hair_index=payload["hairIndex"],
547            feature_index=payload["featureIndex"],
548            decal_index=payload["decalIndex"],
549        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
551    def deserialize_character_minimal_equipments(
552        self, payload: typedefs.JSONObject
553    ) -> character.MinimalEquipments:
554        dyes = None
555        if raw_dyes := payload.get("dyes"):
556            if raw_dyes:
557                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
558        return character.MinimalEquipments(
559            net=self._net, item_hash=payload["itemHash"], dyes=dyes
560        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
562    def deserialize_character_render_data(
563        self, payload: typedefs.JSONObject, /
564    ) -> character.RenderedData:
565        return character.RenderedData(
566            net=self._net,
567            customization=self.deserialize_character_customization(
568                payload["customization"]
569            ),
570            custom_dyes=[
571                self.deserialize_character_dye(dye)
572                for dye in payload["customDyes"]
573                if dye
574            ],
575            equipment=[
576                self.deserialize_character_minimal_equipments(equipment)
577                for equipment in payload["peerView"]["equipment"]
578            ],
579        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
581    def deserialize_available_activity(
582        self, payload: typedefs.JSONObject
583    ) -> activity.AvailableActivity:
584        return activity.AvailableActivity(
585            hash=payload["activityHash"],
586            is_new=payload["isNew"],
587            is_completed=payload["isCompleted"],
588            is_visible=payload["isVisible"],
589            display_level=payload.get("displayLevel"),
590            recommended_light=payload.get("recommendedLight"),
591            difficulty=activity.Difficulty(payload["difficultyTier"]),
592            can_join=payload["canJoin"],
593            can_lead=payload["canLead"],
594        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
596    def deserialize_character_activity(
597        self, payload: typedefs.JSONObject
598    ) -> activity.CharacterActivity:
599        current_mode: typing.Optional[enums.GameMode] = None
600        if raw_current_mode := payload.get("currentActivityModeType"):
601            current_mode = enums.GameMode(raw_current_mode)
602
603        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
604        if raw_current_modes := payload.get("currentActivityModeTypes"):
605            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
606
607        return activity.CharacterActivity(
608            date_started=time.clean_date(payload["dateActivityStarted"]),
609            current_hash=payload["currentActivityHash"],
610            current_mode_hash=payload["currentActivityModeHash"],
611            current_mode=current_mode,
612            current_mode_hashes=payload.get("currentActivityModeHashes"),
613            current_mode_types=current_mode_types,
614            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
615            last_story_hash=payload["lastCompletedStoryHash"],
616            available_activities=[
617                self.deserialize_available_activity(activity_)
618                for activity_ in payload["availableActivities"]
619            ],
620        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
622    def deserialize_profile_items(
623        self, payload: typedefs.JSONObject, /
624    ) -> list[profile.ProfileItemImpl]:
625        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
668    def deserialize_progressions(
669        self, payload: typedefs.JSONObject
670    ) -> progressions.Progression:
671        return progressions.Progression(
672            hash=int(payload["progressionHash"]),
673            level=int(payload["level"]),
674            cap=int(payload["levelCap"]),
675            daily_limit=int(payload["dailyLimit"]),
676            weekly_limit=int(payload["weeklyLimit"]),
677            current_progress=int(payload["currentProgress"]),
678            daily_progress=int(payload["dailyProgress"]),
679            needed=int(payload["progressToNextLevel"]),
680            next_level=int(payload["nextLevelAt"]),
681        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
769    def deserialize_milestone(
770        self, payload: typedefs.JSONObject
771    ) -> milestones.Milestone:
772        start_date: typing.Optional[datetime.datetime] = None
773        if raw_start_date := payload.get("startDate"):
774            start_date = time.clean_date(raw_start_date)
775
776        end_date: typing.Optional[datetime.datetime] = None
777        if raw_end_date := payload.get("endDate"):
778            end_date = time.clean_date(raw_end_date)
779
780        rewards: typing.Optional[
781            collections.Collection[milestones.MilestoneReward]
782        ] = None
783        if raw_rewards := payload.get("rewards"):
784            rewards = [
785                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
786            ]
787
788        activities: typing.Optional[
789            collections.Sequence[milestones.MilestoneActivity]
790        ] = None
791        if raw_activities := payload.get("activities"):
792            activities = [
793                self._deserialize_milestone_activity(active)
794                for active in raw_activities
795            ]
796
797        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
798        if raw_quests := payload.get("availableQuests"):
799            quests = [
800                self._deserialize_milestone_available_quest(quest)
801                for quest in raw_quests
802            ]
803
804        vendors: typing.Optional[
805            collections.Sequence[milestones.MilestoneVendor]
806        ] = None
807        if raw_vendors := payload.get("vendors"):
808            vendors = [
809                milestones.MilestoneVendor(
810                    vendor_hash=vendor["vendorHash"],
811                    preview_itemhash=vendor.get("previewItemHash"),
812                )
813                for vendor in raw_vendors
814            ]
815
816        return milestones.Milestone(
817            hash=payload["milestoneHash"],
818            start_date=start_date,
819            end_date=end_date,
820            order=payload["order"],
821            rewards=rewards,
822            available_quests=quests,
823            activities=activities,
824            vendors=vendors,
825        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
842    def deserialize_characters(
843        self, payload: typedefs.JSONObject
844    ) -> collections.Mapping[int, character.Character]:
845        return {
846            int(char_id): self._set_character_attrs(char)
847            for char_id, char in payload["data"].items()
848        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
850    def deserialize_character(
851        self, payload: typedefs.JSONObject
852    ) -> character.Character:
853        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
855    def deserialize_character_equipments(
856        self, payload: typedefs.JSONObject
857    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
858        return {
859            int(char_id): self.deserialize_profile_items(item)
860            for char_id, item in payload["data"].items()
861        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
863    def deserialize_character_activities(
864        self, payload: typedefs.JSONObject
865    ) -> collections.Mapping[int, activity.CharacterActivity]:
866        return {
867            int(char_id): self.deserialize_character_activity(data)
868            for char_id, data in payload["data"].items()
869        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
871    def deserialize_characters_render_data(
872        self, payload: typedefs.JSONObject
873    ) -> collections.Mapping[int, character.RenderedData]:
874        return {
875            int(char_id): self.deserialize_character_render_data(data)
876            for char_id, data in payload["data"].items()
877        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
879    def deserialize_character_progressions(
880        self, payload: typedefs.JSONObject
881    ) -> character.CharacterProgression:
882        progressions_ = {
883            int(prog_id): self.deserialize_progressions(prog)
884            for prog_id, prog in payload["progressions"].items()
885        }
886
887        factions = {
888            int(faction_id): self._deserialize_factions(faction)
889            for faction_id, faction in payload["factions"].items()
890        }
891
892        milestones_ = {
893            int(milestone_hash): self.deserialize_milestone(milestone)
894            for milestone_hash, milestone in payload["milestones"].items()
895        }
896
897        uninstanced_item_objectives = {
898            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
899            for item_hash, obj in payload["uninstancedItemObjectives"].items()
900        }
901
902        artifact = payload["seasonalArtifact"]
903        seasonal_artifact = season.CharacterScopedArtifact(
904            hash=artifact["artifactHash"],
905            points_used=artifact["pointsUsed"],
906            reset_count=artifact["resetCount"],
907            tiers=[
908                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
909            ],
910        )
911        checklists = payload["checklists"]
912
913        return character.CharacterProgression(
914            progressions=progressions_,
915            factions=factions,
916            checklists=checklists,
917            milestones=milestones_,
918            seasonal_artifact=seasonal_artifact,
919            uninstanced_item_objectives=uninstanced_item_objectives,
920        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
922    def deserialize_character_progressions_mapping(
923        self, payload: typedefs.JSONObject
924    ) -> collections.Mapping[int, character.CharacterProgression]:
925        character_progressions: collections.Mapping[
926            int, character.CharacterProgression
927        ] = {}
928        for char_id, data in payload["data"].items():
929            # A little hack to stop mypy complaining about Mapping <-> dict
930            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
931        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
933    def deserialize_characters_records(
934        self,
935        payload: typedefs.JSONObject,
936    ) -> collections.Mapping[int, records.CharacterRecord]:
937
938        return {
939            int(rec_id): self.deserialize_character_records(
940                rec, record_hashes=payload.get("featuredRecordHashes")
941            )
942            for rec_id, rec in payload["records"].items()
943        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
945    def deserialize_profile_records(
946        self, payload: typedefs.JSONObject
947    ) -> collections.Mapping[int, records.Record]:
948        raw_profile_records = payload["data"]
949        scores = records.RecordScores(
950            current_score=raw_profile_records["score"],
951            legacy_score=raw_profile_records["legacyScore"],
952            lifetime_score=raw_profile_records["lifetimeScore"],
953        )
954        return {
955            int(record_id): self.deserialize_records(
956                record,
957                scores,
958                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
959                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
960            )
961            for record_id, record in raw_profile_records["records"].items()
962        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
 999    def deserialize_craftables_component(
1000        self, payload: typedefs.JSONObject
1001    ) -> components.CraftablesComponent:
1002        return components.CraftablesComponent(
1003            net=self._net,
1004            craftables={
1005                int(item_id): self._deserialize_craftable_item(item)
1006                for item_id, item in payload["craftables"].items()
1007                if item is not None
1008            },
1009            crafting_root_node_hash=payload["craftingRootNodeHash"],
1010        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1012    def deserialize_components(  # noqa: C901 Too complex.
1013        self, payload: typedefs.JSONObject
1014    ) -> components.Component:
1015
1016        profile_: typing.Optional[profile.Profile] = None
1017        if raw_profile := payload.get("profile"):
1018            profile_ = self.deserialize_profile(raw_profile)
1019
1020        profile_progression: typing.Optional[profile.ProfileProgression] = None
1021        if raw_profile_progression := payload.get("profileProgression"):
1022            profile_progression = self.deserialize_profile_progression(
1023                raw_profile_progression
1024            )
1025
1026        profile_currencies: typing.Optional[
1027            collections.Sequence[profile.ProfileItemImpl]
1028        ] = None
1029        if raw_profile_currencies := payload.get("profileCurrencies"):
1030            if "data" in raw_profile_currencies:
1031                profile_currencies = self.deserialize_profile_items(
1032                    raw_profile_currencies["data"]
1033                )
1034
1035        profile_inventories: typing.Optional[
1036            collections.Sequence[profile.ProfileItemImpl]
1037        ] = None
1038        if raw_profile_inventories := payload.get("profileInventory"):
1039            if "data" in raw_profile_inventories:
1040                profile_inventories = self.deserialize_profile_items(
1041                    raw_profile_inventories["data"]
1042                )
1043
1044        profile_records: typing.Optional[
1045            collections.Mapping[int, records.Record]
1046        ] = None
1047
1048        if raw_profile_records_ := payload.get("profileRecords"):
1049            profile_records = self.deserialize_profile_records(raw_profile_records_)
1050
1051        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1052        if raw_characters := payload.get("characters"):
1053            characters = self.deserialize_characters(raw_characters)
1054
1055        character_records: typing.Optional[
1056            collections.Mapping[int, records.CharacterRecord]
1057        ] = None
1058
1059        if raw_character_records := payload.get("characterRecords"):
1060            # Had to do it in two steps..
1061            to_update: typedefs.JSONObject = {}
1062            for _, data in raw_character_records["data"].items():
1063                for record_id, record in data.items():
1064                    to_update[record_id] = record
1065
1066            character_records = {
1067                int(rec_id): self.deserialize_character_records(
1068                    rec, record_hashes=to_update.get("featuredRecordHashes")
1069                )
1070                for rec_id, rec in to_update["records"].items()
1071            }
1072
1073        character_equipments: typing.Optional[
1074            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1075        ] = None
1076        if raw_character_equips := payload.get("characterEquipment"):
1077            character_equipments = self.deserialize_character_equipments(
1078                raw_character_equips
1079            )
1080
1081        character_inventories: typing.Optional[
1082            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1083        ] = None
1084        if raw_character_inventories := payload.get("characterInventories"):
1085            if "data" in raw_character_inventories:
1086                character_inventories = self.deserialize_character_equipments(
1087                    raw_character_inventories
1088                )
1089
1090        character_activities: typing.Optional[
1091            collections.Mapping[int, activity.CharacterActivity]
1092        ] = None
1093        if raw_char_acts := payload.get("characterActivities"):
1094            character_activities = self.deserialize_character_activities(raw_char_acts)
1095
1096        character_render_data: typing.Optional[
1097            collections.Mapping[int, character.RenderedData]
1098        ] = None
1099        if raw_character_render_data := payload.get("characterRenderData"):
1100            character_render_data = self.deserialize_characters_render_data(
1101                raw_character_render_data
1102            )
1103
1104        character_progressions: typing.Optional[
1105            collections.Mapping[int, character.CharacterProgression]
1106        ] = None
1107
1108        if raw_character_progressions := payload.get("characterProgressions"):
1109            character_progressions = self.deserialize_character_progressions_mapping(
1110                raw_character_progressions
1111            )
1112
1113        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1114        if raw_profile_string_vars := payload.get("profileStringVariables"):
1115            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1116
1117        character_string_vars: typing.Optional[
1118            collections.Mapping[int, collections.Mapping[int, int]]
1119        ] = None
1120        if raw_character_string_vars := payload.get("characterStringVariables"):
1121            character_string_vars = {
1122                int(char_id): data["integerValuesByHash"]
1123                for char_id, data in raw_character_string_vars["data"].items()
1124            }
1125
1126        metrics: typing.Optional[
1127            collections.Sequence[
1128                collections.Mapping[
1129                    int, tuple[bool, typing.Optional[records.Objective]]
1130                ]
1131            ]
1132        ] = None
1133        root_node_hash: typing.Optional[int] = None
1134
1135        if raw_metrics := payload.get("metrics"):
1136            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1137            metrics = [
1138                {
1139                    int(metrics_hash): (
1140                        data["invisible"],
1141                        self.deserialize_objectives(data["objectiveProgress"])
1142                        if "objectiveProgress" in data
1143                        else None,
1144                    )
1145                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1146                }
1147            ]
1148        transitory: typing.Optional[fireteams.FireteamParty] = None
1149        if raw_transitory := payload.get("profileTransitoryData"):
1150            if "data" in raw_transitory:
1151                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1152
1153        item_components: typing.Optional[components.ItemsComponent] = None
1154        if raw_item_components := payload.get("itemComponents"):
1155            item_components = self.deserialize_items_component(raw_item_components)
1156
1157        profile_plugsets: typing.Optional[
1158            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1159        ] = None
1160
1161        if raw_profile_plugs := payload.get("profilePlugSets"):
1162            profile_plugsets = {
1163                int(index): [self.deserialize_plug_item_state(state) for state in data]
1164                for index, data in raw_profile_plugs["data"]["plugs"].items()
1165            }
1166
1167        character_plugsets: typing.Optional[
1168            collections.Mapping[
1169                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1170            ]
1171        ] = None
1172        if raw_char_plugsets := payload.get("characterPlugSets"):
1173            character_plugsets = {
1174                int(char_id): {
1175                    int(index): [
1176                        self.deserialize_plug_item_state(state) for state in data
1177                    ]
1178                    for index, data in inner["plugs"].items()
1179                }
1180                for char_id, inner in raw_char_plugsets["data"].items()
1181            }
1182
1183        character_collectibles: typing.Optional[
1184            collections.Mapping[int, items.Collectible]
1185        ] = None
1186        if raw_character_collectibles := payload.get("characterCollectibles"):
1187            character_collectibles = {
1188                int(char_id): self._deserialize_collectible(data)
1189                for char_id, data in raw_character_collectibles["data"].items()
1190            }
1191
1192        profile_collectibles: typing.Optional[items.Collectible] = None
1193        if raw_profile_collectibles := payload.get("profileCollectibles"):
1194            profile_collectibles = self._deserialize_collectible(
1195                raw_profile_collectibles["data"]
1196            )
1197
1198        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1199        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1200            profile_nodes = {
1201                int(node_hash): self._deserialize_node(node)
1202                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1203            }
1204
1205        character_nodes: typing.Optional[
1206            collections.Mapping[int, collections.Mapping[int, records.Node]]
1207        ] = None
1208        if raw_character_nodes := payload.get("characterPresentationNodes"):
1209            character_nodes = {
1210                int(char_id): {
1211                    int(node_hash): self._deserialize_node(node)
1212                    for node_hash, node in each_character["nodes"].items()
1213                }
1214                for char_id, each_character in raw_character_nodes["data"].items()
1215            }
1216
1217        platform_silver: typing.Optional[
1218            collections.Mapping[str, profile.ProfileItemImpl]
1219        ] = None
1220        if raw_platform_silver := payload.get("platformSilver"):
1221            if "data" in raw_platform_silver:
1222                platform_silver = {
1223                    platform_name: self.deserialize_profile_item(item)
1224                    for platform_name, item in raw_platform_silver["data"][
1225                        "platformSilver"
1226                    ].items()
1227                }
1228
1229        character_currency_lookups: typing.Optional[
1230            collections.Mapping[int, collections.Sequence[items.Currency]]
1231        ] = None
1232        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1233            if "data" in raw_char_lookups:
1234                character_currency_lookups = {
1235                    int(char_id): self._deserialize_currencies(currencie)
1236                    for char_id, currencie in raw_char_lookups["data"].items()
1237                }
1238
1239        character_craftables: typing.Optional[
1240            collections.Mapping[int, components.CraftablesComponent]
1241        ] = None
1242        if raw_character_craftables := payload.get("characterCraftables"):
1243
1244            if "data" in raw_character_craftables:
1245                character_craftables = {
1246                    int(char_id): self.deserialize_craftables_component(craftable)
1247                    for char_id, craftable in raw_character_craftables["data"].items()
1248                }
1249
1250        return components.Component(
1251            profiles=profile_,
1252            profile_progression=profile_progression,
1253            profile_currencies=profile_currencies,
1254            profile_inventories=profile_inventories,
1255            profile_records=profile_records,
1256            characters=characters,
1257            character_records=character_records,
1258            character_equipments=character_equipments,
1259            character_inventories=character_inventories,
1260            character_activities=character_activities,
1261            character_render_data=character_render_data,
1262            character_progressions=character_progressions,
1263            profile_string_variables=profile_string_vars,
1264            character_string_variables=character_string_vars,
1265            metrics=metrics,
1266            root_node_hash=root_node_hash,
1267            transitory=transitory,
1268            item_components=item_components,
1269            profile_plugsets=profile_plugsets,
1270            character_plugsets=character_plugsets,
1271            character_collectibles=character_collectibles,
1272            profile_collectibles=profile_collectibles,
1273            profile_nodes=profile_nodes,
1274            character_nodes=character_nodes,
1275            platform_silver=platform_silver,
1276            character_currency_lookups=character_currency_lookups,
1277            character_craftables=character_craftables,
1278        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1280    def deserialize_items_component(
1281        self, payload: typedefs.JSONObject
1282    ) -> components.ItemsComponent:
1283        instances: typing.Optional[
1284            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1285        ] = None
1286        if raw_instances := payload.get("instances"):
1287            instances = [
1288                {
1289                    int(ins_id): self.deserialize_instanced_item(item)
1290                    for ins_id, item in raw_instances["data"].items()
1291                }
1292            ]
1293
1294        render_data: typing.Optional[
1295            collections.Mapping[int, tuple[bool, dict[int, int]]]
1296        ] = None
1297        if raw_render_data := payload.get("renderData"):
1298            render_data = {
1299                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1300                for ins_id, data in raw_render_data["data"].items()
1301            }
1302
1303        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1304        if raw_stats := payload.get("stats"):
1305            builder: collections.Mapping[int, items.ItemStatsView] = {}
1306            for ins_id, stat in raw_stats["data"].items():
1307                for _, items_ in stat.items():
1308                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1309            stats = builder
1310
1311        sockets: typing.Optional[
1312            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1313        ] = None
1314        if raw_sockets := payload.get("sockets"):
1315            sockets = {
1316                int(ins_id): [
1317                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1318                ]
1319                for ins_id, item in raw_sockets["data"].items()
1320            }
1321
1322        objeectives: typing.Optional[
1323            collections.Mapping[int, collections.Sequence[records.Objective]]
1324        ] = None
1325        if raw_objectives := payload.get("objectives"):
1326            objeectives = {
1327                int(ins_id): [self.deserialize_objectives(objective)]
1328                for ins_id, data in raw_objectives["data"].items()
1329                for objective in data["objectives"]
1330            }
1331
1332        perks: typing.Optional[
1333            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1334        ] = None
1335        if raw_perks := payload.get("perks"):
1336            perks = {
1337                int(ins_id): [
1338                    self.deserialize_item_perk(perk) for perk in item["perks"]
1339                ]
1340                for ins_id, item in raw_perks["data"].items()
1341            }
1342
1343        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1344        if raw_plug_states := payload.get("plugStates"):
1345            pending_states: list[items.PlugItemState] = []
1346            for _, plug in raw_plug_states["data"].items():
1347                pending_states.append(self.deserialize_plug_item_state(plug))
1348            plug_states = pending_states
1349
1350        reusable_plugs: typing.Optional[
1351            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1352        ] = None
1353        if raw_re_plugs := payload.get("reusablePlugs"):
1354            reusable_plugs = {
1355                int(ins_id): [
1356                    self.deserialize_plug_item_state(state) for state in inner
1357                ]
1358                for ins_id, plug in raw_re_plugs["data"].items()
1359                for inner in list(plug["plugs"].values())
1360            }
1361
1362        plug_objectives: typing.Optional[
1363            collections.Mapping[
1364                int, collections.Mapping[int, collections.Collection[records.Objective]]
1365            ]
1366        ] = None
1367        if raw_plug_objectives := payload.get("plugObjectives"):
1368            plug_objectives = {
1369                int(ins_id): {
1370                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1371                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1372                }
1373                for ins_id, inner in raw_plug_objectives["data"].items()
1374            }
1375
1376        return components.ItemsComponent(
1377            sockets=sockets,
1378            stats=stats,
1379            render_data=render_data,
1380            instances=instances,
1381            objectives=objeectives,
1382            perks=perks,
1383            plug_states=plug_states,
1384            reusable_plugs=reusable_plugs,
1385            plug_objectives=plug_objectives,
1386        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1388    def deserialize_character_component(  # type: ignore[call-arg]
1389        self, payload: typedefs.JSONObject
1390    ) -> components.CharacterComponent:
1391
1392        character_: typing.Optional[character.Character] = None
1393        if raw_singuler_character := payload.get("character"):
1394            character_ = self.deserialize_character(raw_singuler_character["data"])
1395
1396        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1397        if raw_inventory := payload.get("inventory"):
1398            if "data" in raw_inventory:
1399                inventory = self.deserialize_profile_items(raw_inventory["data"])
1400
1401        activities: typing.Optional[activity.CharacterActivity] = None
1402        if raw_activities := payload.get("activities"):
1403            activities = self.deserialize_character_activity(raw_activities["data"])
1404
1405        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1406        if raw_equipments := payload.get("equipment"):
1407            equipment = self.deserialize_profile_items(raw_equipments["data"])
1408
1409        progressions_: typing.Optional[character.CharacterProgression] = None
1410        if raw_progressions := payload.get("progressions"):
1411            progressions_ = self.deserialize_character_progressions(
1412                raw_progressions["data"]
1413            )
1414
1415        render_data: typing.Optional[character.RenderedData] = None
1416        if raw_render_data := payload.get("renderData"):
1417            render_data = self.deserialize_character_render_data(
1418                raw_render_data["data"]
1419            )
1420
1421        character_records: typing.Optional[
1422            collections.Mapping[int, records.CharacterRecord]
1423        ] = None
1424        if raw_char_records := payload.get("records"):
1425            character_records = self.deserialize_characters_records(
1426                raw_char_records["data"]
1427            )
1428
1429        item_components: typing.Optional[components.ItemsComponent] = None
1430        if raw_item_components := payload.get("itemComponents"):
1431            item_components = self.deserialize_items_component(raw_item_components)
1432
1433        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1434        if raw_nodes := payload.get("presentationNodes"):
1435            nodes = {
1436                int(node_hash): self._deserialize_node(node)
1437                for node_hash, node in raw_nodes["data"]["nodes"].items()
1438            }
1439
1440        collectibles: typing.Optional[items.Collectible] = None
1441        if raw_collectibles := payload.get("collectibles"):
1442            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1443
1444        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1445        if raw_currencies := payload.get("currencyLookups"):
1446            if "data" in raw_currencies:
1447                currency_lookups = self._deserialize_currencies(raw_currencies)
1448
1449        return components.CharacterComponent(
1450            activities=activities,
1451            equipment=equipment,
1452            inventory=inventory,
1453            progressions=progressions_,
1454            render_data=render_data,
1455            character=character_,
1456            character_records=character_records,
1457            profile_records=None,
1458            item_components=item_components,
1459            currency_lookups=currency_lookups,
1460            collectibles=collectibles,
1461            nodes=nodes,
1462        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.entity.SearchableEntity]:
1490    def deserialize_inventory_results(
1491        self, payload: typedefs.JSONObject
1492    ) -> iterators.Iterator[entity.SearchableEntity]:
1493        suggested_words: list[str] = payload["suggestedWords"]
1494
1495        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1496            return s if not typedefs.is_unknown(s) else undefined.UNDEFINED
1497
1498        return iterators.Iterator(
1499            [
1500                entity.SearchableEntity(
1501                    net=self._net,
1502                    hash=data["hash"],
1503                    entity_type=data["entityType"],
1504                    weight=data["weight"],
1505                    suggested_words=suggested_words,
1506                    name=data["displayProperties"]["name"],
1507                    has_icon=data["displayProperties"]["hasIcon"],
1508                    description=_check_unknown(
1509                        data["displayProperties"]["description"]
1510                    ),
1511                    icon=assets.Image(data["displayProperties"]["icon"]),
1512                )
1513                for data in payload["results"]["results"]
1514            ]
1515        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1544    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1545        self, payload: typedefs.JSONObject, /
1546    ) -> entity.InventoryEntity:
1547
1548        props = self._set_entity_attrs(payload)
1549        objects = self._deserialize_inventory_item_objects(payload)
1550
1551        collectible_hash: typing.Optional[int] = None
1552        if raw_collectible_hash := payload.get("collectibleHash"):
1553            collectible_hash = int(raw_collectible_hash)
1554
1555        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1556        if raw_second_icon := payload.get("secondaryIcon"):
1557            secondary_icon = assets.Image(raw_second_icon)
1558
1559        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1560        if raw_second_overlay := payload.get("secondaryOverlay"):
1561            secondary_overlay = assets.Image(raw_second_overlay)
1562
1563        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1564        if raw_second_special := payload.get("secondarySpecial"):
1565            secondary_special = assets.Image(raw_second_special)
1566
1567        screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED
1568        if raw_screenshot := payload.get("screenshot"):
1569            screenshot = assets.Image(raw_screenshot)
1570
1571        watermark_icon: typing.Optional[assets.Image] = None
1572        if raw_watermark_icon := payload.get("iconWatermark"):
1573            watermark_icon = assets.Image(raw_watermark_icon)
1574
1575        watermark_shelved: typing.Optional[assets.Image] = None
1576        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1577            watermark_shelved = assets.Image(raw_watermark_shelved)
1578
1579        about: undefined.UndefinedOr[str] = undefined.UNDEFINED
1580        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1581            raw_about
1582        ):
1583            about = raw_about
1584
1585        ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED
1586        if (
1587            raw_ui_style := payload.get("uiItemDisplayStyle")
1588        ) and not typedefs.is_unknown(raw_ui_style):
1589            ui_item_style = raw_ui_style
1590
1591        tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1592        if (
1593            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1594        ) and not typedefs.is_unknown(raw_tier_and_name):
1595            tier_and_name = raw_tier_and_name
1596
1597        type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1598        if (
1599            raw_type_name := payload.get("itemTypeDisplayName")
1600        ) and not typedefs.is_unknown(raw_type_name):
1601            type_name = raw_type_name
1602
1603        display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED
1604        if (
1605            raw_display_source := payload.get("displaySource")
1606        ) and not typedefs.is_unknown(raw_display_source):
1607            display_source = raw_display_source
1608
1609        lorehash: typing.Optional[int] = None
1610        if raw_lore_hash := payload.get("loreHash"):
1611            lorehash = int(raw_lore_hash)
1612
1613        summary_hash: typing.Optional[int] = None
1614        if raw_summary_hash := payload.get("summaryItemHash"):
1615            summary_hash = raw_summary_hash
1616
1617        breaker_type_hash: typing.Optional[int] = None
1618        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1619            breaker_type_hash = int(raw_breaker_type_hash)
1620
1621        damage_types: typing.Optional[collections.Sequence[int]] = None
1622        if raw_damage_types := payload.get("damageTypes"):
1623            damage_types = [int(type_) for type_ in raw_damage_types]
1624
1625        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1626        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1627            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1628
1629        default_damagetype_hash: typing.Optional[int] = None
1630        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1631            default_damagetype_hash = int(raw_defaultdmg_hash)
1632
1633        emblem_objective_hash: typing.Optional[int] = None
1634        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1635            emblem_objective_hash = int(raw_emblem_obj_hash)
1636
1637        tier_type: typing.Optional[enums.TierType] = None
1638        tier: typing.Optional[enums.ItemTier] = None
1639        bucket_hash: typing.Optional[int] = None
1640        recovery_hash: typing.Optional[int] = None
1641        tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED
1642        isinstance_item: bool = False
1643        expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED
1644        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED
1645        suppress_expiration: bool = False
1646        max_stack_size: typing.Optional[int] = None
1647        stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED
1648
1649        if inventory := payload.get("inventory"):
1650            tier_type = enums.TierType(int(inventory["tierType"]))
1651            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1652            bucket_hash = int(inventory["bucketTypeHash"])
1653            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1654            tier_name = inventory["tierTypeName"]
1655            isinstance_item = inventory["isInstanceItem"]
1656            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1657            max_stack_size = int(inventory["maxStackSize"])
1658
1659            try:
1660                stack_label = inventory["stackUniqueLabel"]
1661            except KeyError:
1662                pass
1663
1664        return entity.InventoryEntity(
1665            net=self._net,
1666            collectible_hash=collectible_hash,
1667            name=props.name,
1668            about=about,
1669            emblem_objective_hash=emblem_objective_hash,
1670            suppress_expiration=suppress_expiration,
1671            max_stack_size=max_stack_size,
1672            stack_label=stack_label,
1673            tier=tier,
1674            tier_type=tier_type,
1675            tier_name=tier_name,
1676            bucket_hash=bucket_hash,
1677            recovery_bucket_hash=recovery_hash,
1678            isinstance_item=isinstance_item,
1679            expire_in_orbit_message=expire_in_orbit_message,
1680            expiration_tooltip=expire_tool_tip,
1681            lore_hash=lorehash,
1682            type_and_tier_name=tier_and_name,
1683            summary_hash=summary_hash,
1684            ui_display_style=ui_item_style,
1685            type_name=type_name,
1686            breaker_type_hash=breaker_type_hash,
1687            description=props.description,
1688            display_source=display_source,
1689            hash=props.hash,
1690            damage_types=damage_types,
1691            index=props.index,
1692            icon=props.icon,
1693            has_icon=props.has_icon,
1694            screenshot=screenshot,
1695            watermark_icon=watermark_icon,
1696            watermark_shelved=watermark_shelved,
1697            secondary_icon=secondary_icon,
1698            secondary_overlay=secondary_overlay,
1699            secondary_special=secondary_special,
1700            type=enums.ItemType(int(payload["itemType"])),
1701            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1702            trait_ids=[trait for trait in payload.get("traitIds", [])],
1703            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1704            item_class=enums.Class(int(payload["classType"])),
1705            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1706            breaker_type=int(payload["breakerType"]),
1707            default_damagetype=int(payload["defaultDamageType"]),
1708            default_damagetype_hash=default_damagetype_hash,
1709            damagetype_hashes=damagetype_hashes,
1710            tooltip_notifications=payload["tooltipNotifications"],
1711            not_transferable=payload["nonTransferrable"],
1712            allow_actions=payload["allowActions"],
1713            is_equippable=payload["equippable"],
1714            objects=objects,
1715            background_colors=payload.get("backgroundColor", {}),
1716            season_hash=payload.get("seasonHash"),
1717            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1718        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1720    def deserialize_objective_entity(
1721        self, payload: typedefs.JSONObject, /
1722    ) -> entity.ObjectiveEntity:
1723        props = self._set_entity_attrs(payload)
1724        return entity.ObjectiveEntity(
1725            net=self._net,
1726            hash=props.hash,
1727            index=props.index,
1728            description=props.description,
1729            name=props.name,
1730            has_icon=props.has_icon,
1731            icon=props.icon,
1732            unlock_value_hash=payload["unlockValueHash"],
1733            completion_value=payload["completionValue"],
1734            scope=entity.GatingScope(int(payload["scope"])),
1735            location_hash=payload["locationHash"],
1736            allowed_negative_value=payload["allowNegativeValue"],
1737            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1738            counting_downward=payload["isCountingDownward"],
1739            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1740            progress_description=payload["progressDescription"],
1741            perks=payload["perks"],
1742            stats=payload["stats"],
1743            minimum_visibility=payload["minimumVisibilityThreshold"],
1744            allow_over_completion=payload["allowOvercompletion"],
1745            show_value_style=payload["showValueOnComplete"],
1746            display_only_objective=payload["isDisplayOnlyObjective"],
1747            complete_value_style=entity.ValueUIStyle(
1748                int(payload["completedValueStyle"])
1749            ),
1750            progress_value_style=entity.ValueUIStyle(
1751                int(payload["inProgressValueStyle"])
1752            ),
1753            ui_label=payload["uiLabel"],
1754            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1755        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1783    def deserialize_activity(
1784        self,
1785        payload: typedefs.JSONObject,
1786        /,
1787    ) -> activity.Activity:
1788        period = time.clean_date(payload["period"])
1789        details = payload["activityDetails"]
1790        ref_id = int(details["referenceId"])
1791        instance_id = int(details["instanceId"])
1792        mode = enums.GameMode(details["mode"])
1793        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1794        is_private = details["isPrivate"]
1795        membership_type = enums.MembershipType(int(details["membershipType"]))
1796
1797        # Since we're using the same fields for post activity method
1798        # this check is required since post activity doesn't values values
1799        values = self._deserialize_activity_values(payload["values"])
1800
1801        return activity.Activity(
1802            net=self._net,
1803            hash=ref_id,
1804            instance_id=instance_id,
1805            mode=mode,
1806            modes=modes,
1807            is_private=is_private,
1808            membership_type=membership_type,
1809            occurred_at=period,
1810            values=values,
1811        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.activity.Activity]:
1813    def deserialize_activities(
1814        self, payload: typedefs.JSONObject
1815    ) -> iterators.Iterator[activity.Activity]:
1816        return iterators.Iterator(
1817            [
1818                self.deserialize_activity(activity_)
1819                for activity_ in payload["activities"]
1820            ]
1821        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1823    def deserialize_extended_weapon_values(
1824        self, payload: typedefs.JSONObject
1825    ) -> activity.ExtendedWeaponValues:
1826
1827        assists: typing.Optional[int] = None
1828        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1829            assists = raw_assists["basic"]["value"]
1830        assists_damage: typing.Optional[int] = None
1831
1832        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1833            assists_damage = raw_assists_damage["basic"]["value"]
1834
1835        return activity.ExtendedWeaponValues(
1836            reference_id=int(payload["referenceId"]),
1837            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1838            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1839                "value"
1840            ],
1841            assists=assists,
1842            assists_damage=assists_damage,
1843            precision_kills_percentage=(
1844                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1845                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1846                    "displayValue"
1847                ],
1848            ),
1849        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1872    def deserialize_post_activity_player(
1873        self, payload: typedefs.JSONObject, /
1874    ) -> activity.PostActivityPlayer:
1875        player = payload["player"]
1876
1877        class_hash: typedefs.NoneOr[int] = None
1878        if (class_hash := player.get("classHash")) is not None:
1879            class_hash = class_hash
1880
1881        race_hash: typedefs.NoneOr[int] = None
1882        if (race_hash := player.get("raceHash")) is not None:
1883            race_hash = race_hash
1884
1885        gender_hash: typedefs.NoneOr[int] = None
1886        if (gender_hash := player.get("genderHash")) is not None:
1887            gender_hash = gender_hash
1888
1889        character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED
1890        if (
1891            character_class := player.get("characterClass")
1892        ) and not typedefs.is_unknown(character_class):
1893            character_class = character_class
1894
1895        character_level: typedefs.NoneOr[int] = None
1896        if (character_level := player.get("characterLevel")) is not None:
1897            character_level = character_level
1898
1899        return activity.PostActivityPlayer(
1900            standing=int(payload["standing"]),
1901            score=int(payload["score"]["basic"]["value"]),
1902            character_id=payload["characterId"],
1903            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1904            character_class=character_class,
1905            character_level=character_level,
1906            race_hash=race_hash,
1907            gender_hash=gender_hash,
1908            class_hash=class_hash,
1909            light_level=int(player["lightLevel"]),
1910            emblem_hash=int(player["emblemHash"]),
1911            values=self._deserialize_activity_values(payload["values"]),
1912            extended_values=self._deserialize_extended_values(payload["extended"]),
1913        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1925    def deserialize_post_activity(
1926        self, payload: typedefs.JSONObject
1927    ) -> activity.PostActivity:
1928        period = time.clean_date(payload["period"])
1929        details = payload["activityDetails"]
1930        ref_id = int(details["referenceId"])
1931        instance_id = int(details["instanceId"])
1932        mode = enums.GameMode(details["mode"])
1933        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1934        is_private = details["isPrivate"]
1935        membership_type = enums.MembershipType(int(details["membershipType"]))
1936        return activity.PostActivity(
1937            net=self._net,
1938            hash=ref_id,
1939            membership_type=membership_type,
1940            instance_id=instance_id,
1941            mode=mode,
1942            modes=modes,
1943            is_private=is_private,
1944            occurred_at=period,
1945            starting_phase=int(payload["startingPhaseIndex"]),
1946            players=[
1947                self.deserialize_post_activity_player(player)
1948                for player in payload["entries"]
1949            ],
1950            teams=[
1951                self._deserialize_post_activity_team(team) for team in payload["teams"]
1952            ],
1953        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1991    def deserialize_aggregated_activity(
1992        self, payload: typedefs.JSONObject
1993    ) -> activity.AggregatedActivity:
1994        return activity.AggregatedActivity(
1995            hash=int(payload["activityHash"]),
1996            values=self._deserialize_aggregated_activity_values(payload["values"]),
1997        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> aiobungie.Iterator[aiobungie.crates.activity.AggregatedActivity]:
1999    def deserialize_aggregated_activities(
2000        self, payload: typedefs.JSONObject
2001    ) -> iterators.Iterator[activity.AggregatedActivity]:
2002        return iterators.Iterator(
2003            [
2004                self.deserialize_aggregated_activity(activity)
2005                for activity in payload["activities"]
2006            ]
2007        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
2009    def deserialize_linked_profiles(
2010        self, payload: typedefs.JSONObject
2011    ) -> profile.LinkedProfile:
2012        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2013        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2014        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2015
2016        if raw_profile := payload.get("profiles"):
2017            for pfile in raw_profile:
2018                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2019
2020        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2021            for raw_error_pfile in raw_profiles_with_errors:
2022                if error_pfile := raw_error_pfile.get("infoCard"):
2023                    error_profiles_vec.append(
2024                        self.deserialize_destiny_membership(error_pfile)
2025                    )
2026
2027        return profile.LinkedProfile(
2028            net=self._net,
2029            bungie=bungie_user,
2030            profiles=profiles_vec,
2031            profiles_with_errors=error_profiles_vec,
2032        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2034    def deserialize_clan_banners(
2035        self, payload: typedefs.JSONObject
2036    ) -> collections.Sequence[clans.ClanBanner]:
2037        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2038        if banners := payload.get("clanBannerDecals"):
2039            for k, v in banners.items():
2040                banner_obj = clans.ClanBanner(
2041                    id=int(k),
2042                    foreground=assets.Image(v["foregroundPath"]),
2043                    background=assets.Image(v["backgroundPath"]),
2044                )
2045                banners_seq.append(banner_obj)
2046        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2048    def deserialize_public_milestone_content(
2049        self, payload: typedefs.JSONObject
2050    ) -> milestones.MilestoneContent:
2051        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2052        if raw_categories := payload.get("itemCategories"):
2053            for item in raw_categories:
2054                title = undefined.UNDEFINED
2055                if raw_title := item.get("title"):
2056                    if raw_title != typedefs.Unknown:
2057                        title = raw_title
2058                if raw_hashes := item.get("itemHashes"):
2059                    hashes: collections.Sequence[int] = raw_hashes
2060
2061                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2062
2063        about = undefined.UNDEFINED
2064        if (raw_about := payload["about"]) != typedefs.Unknown:
2065            about = raw_about
2066
2067        status = undefined.UNDEFINED
2068        if (raw_status := payload["status"]) != typedefs.Unknown:
2069            status = raw_status
2070
2071        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2072        if raw_tips := payload.get("tips"):
2073            for raw_tip in raw_tips:
2074                if raw_tip == typedefs.Unknown:
2075                    raw_tip = undefined.UNDEFINED
2076                tips.append(raw_tip)
2077
2078        return milestones.MilestoneContent(
2079            about=about, status=status, tips=tips, items=items_categoris
2080        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2082    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2083        name = undefined.UNDEFINED
2084        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2085            name = raw_name
2086
2087        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2088
2089        if raw_bungie_user := payload.get("bungieNetUser"):
2090            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2091
2092        return friends.Friend(
2093            net=self._net,
2094            id=int(payload["lastSeenAsMembershipId"]),
2095            name=name,
2096            code=payload.get("bungieGlobalDisplayNameCode"),
2097            relationship=enums.Relationship(payload["relationship"]),
2098            user=bungie_user,
2099            online_status=enums.Presence(payload["onlineStatus"]),
2100            online_title=payload["onlineTitle"],
2101            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2102        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2104    def deserialize_friends(
2105        self, payload: typedefs.JSONObject
2106    ) -> collections.Sequence[friends.Friend]:
2107        mut_seq: typing.MutableSequence[friends.Friend] = []
2108        if raw_friends := payload.get("friends"):
2109            for friend in raw_friends:
2110                mut_seq.append(self.deserialize_friend(friend))
2111        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2113    def deserialize_friend_requests(
2114        self, payload: typedefs.JSONObject
2115    ) -> friends.FriendRequestView:
2116        incoming: typing.MutableSequence[friends.Friend] = []
2117        outgoing: typing.MutableSequence[friends.Friend] = []
2118
2119        if raw_incoming_requests := payload.get("incomingRequests"):
2120            for incoming_request in raw_incoming_requests:
2121                incoming.append(self.deserialize_friend(incoming_request))
2122
2123        if raw_outgoing_requests := payload.get("outgoingRequests"):
2124            for outgoing_request in raw_outgoing_requests:
2125                outgoing.append(self.deserialize_friend(outgoing_request))
2126
2127        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2152    def deserialize_fireteams(
2153        self, payload: typedefs.JSONObject
2154    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2155        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2156
2157        result: list[typedefs.JSONObject]
2158        if not (result := payload["results"]):
2159            return None
2160        for elem in result:
2161            fireteams_.append(
2162                self._set_fireteam_fields(
2163                    elem, total_results=int(payload["totalResults"])
2164                )
2165            )
2166        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2168    def deserialize_fireteam_destiny_users(
2169        self, payload: typedefs.JSONObject
2170    ) -> fireteams.FireteamUser:
2171        destiny_obj = self.deserialize_destiny_membership(payload)
2172        # We could helpers.just return a DestinyMembership object but this is
2173        # missing the fireteam display name and id fields.
2174        return fireteams.FireteamUser(
2175            net=self._net,
2176            id=destiny_obj.id,
2177            code=destiny_obj.code,
2178            icon=destiny_obj.icon,
2179            types=destiny_obj.types,
2180            type=destiny_obj.type,
2181            is_public=destiny_obj.is_public,
2182            crossave_override=destiny_obj.crossave_override,
2183            name=destiny_obj.name,
2184            last_seen_name=destiny_obj.last_seen_name,
2185            fireteam_display_name=payload["FireteamDisplayName"],
2186            fireteam_membership_id=enums.MembershipType(
2187                payload["FireteamMembershipType"]
2188            ),
2189        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2191    def deserialize_fireteam_members(
2192        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2193    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2194        members_: list[fireteams.FireteamMember] = []
2195        if members := payload.get("Members" if not alternatives else "Alternates"):
2196            for member in members:
2197                bungie_fields = self.deserialize_partial_bungie_user(member)
2198                members_fields = fireteams.FireteamMember(
2199                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2200                    has_microphone=member["hasMicrophone"],
2201                    character_id=int(member["characterId"]),
2202                    date_joined=time.clean_date(member["dateJoined"]),
2203                    last_platform_invite_date=time.clean_date(
2204                        member["lastPlatformInviteAttemptDate"]
2205                    ),
2206                    last_platform_invite_result=int(
2207                        member["lastPlatformInviteAttemptResult"]
2208                    ),
2209                    net=self._net,
2210                    name=bungie_fields.name,
2211                    id=bungie_fields.id,
2212                    icon=bungie_fields.icon,
2213                    is_public=bungie_fields.is_public,
2214                    crossave_override=bungie_fields.crossave_override,
2215                    types=bungie_fields.types,
2216                    type=bungie_fields.type,
2217                )
2218                members_.append(members_fields)
2219        else:
2220            return None
2221        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2223    def deserialize_available_fireteams(
2224        self,
2225        data: typedefs.JSONObject,
2226        *,
2227        no_results: bool = False,
2228    ) -> typing.Union[
2229        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2230    ]:
2231        fireteams_: list[fireteams.AvailableFireteam] = []
2232
2233        # This needs to be used outside the results
2234        # JSON key.
2235        if no_results is True:
2236            payload = data
2237
2238        if result := payload.get("results"):
2239
2240            for fireteam in result:
2241                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2242                fireteams_fields = fireteams.AvailableFireteam(
2243                    id=found_fireteams.id,
2244                    group_id=found_fireteams.group_id,
2245                    platform=found_fireteams.platform,
2246                    activity_type=found_fireteams.activity_type,
2247                    is_immediate=found_fireteams.is_immediate,
2248                    is_public=found_fireteams.is_public,
2249                    is_valid=found_fireteams.is_valid,
2250                    owner_id=found_fireteams.owner_id,
2251                    player_slot_count=found_fireteams.player_slot_count,
2252                    available_player_slots=found_fireteams.available_player_slots,
2253                    available_alternate_slots=found_fireteams.available_alternate_slots,
2254                    title=found_fireteams.title,
2255                    date_created=found_fireteams.date_created,
2256                    locale=found_fireteams.locale,
2257                    last_modified=found_fireteams.last_modified,
2258                    total_results=found_fireteams.total_results,
2259                    members=self.deserialize_fireteam_members(payload),
2260                    alternatives=self.deserialize_fireteam_members(
2261                        payload, alternatives=True
2262                    ),
2263                )
2264            fireteams_.append(fireteams_fields)
2265            if no_results:
2266                return fireteams_fields
2267        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2269    def deserialize_fireteam_party(
2270        self, payload: typedefs.JSONObject
2271    ) -> fireteams.FireteamParty:
2272        last_destination_hash: typing.Optional[int] = None
2273        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2274            last_destination_hash = int(raw_dest_hash)
2275
2276        return fireteams.FireteamParty(
2277            members=[
2278                self._deserialize_fireteam_party_member(member)
2279                for member in payload["partyMembers"]
2280            ],
2281            activity=self._deserialize_fireteam_party_current_activity(
2282                payload["currentActivity"]
2283            ),
2284            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2285            last_destination_hash=last_destination_hash,
2286            tracking=payload["tracking"],
2287        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2334    def deserialize_seasonal_artifact(
2335        self, payload: typedefs.JSONObject
2336    ) -> season.Artifact:
2337        if raw_artifact := payload.get("seasonalArtifact"):
2338            if points := raw_artifact.get("pointProgression"):
2339                points_prog = progressions.Progression(
2340                    hash=points["progressionHash"],
2341                    level=points["level"],
2342                    cap=points["levelCap"],
2343                    daily_limit=points["dailyLimit"],
2344                    weekly_limit=points["weeklyLimit"],
2345                    current_progress=points["currentProgress"],
2346                    daily_progress=points["dailyProgress"],
2347                    needed=points["progressToNextLevel"],
2348                    next_level=points["nextLevelAt"],
2349                )
2350
2351            if bonus := raw_artifact.get("powerBonusProgression"):
2352                power_bonus_prog = progressions.Progression(
2353                    hash=bonus["progressionHash"],
2354                    level=bonus["level"],
2355                    cap=bonus["levelCap"],
2356                    daily_limit=bonus["dailyLimit"],
2357                    weekly_limit=bonus["weeklyLimit"],
2358                    current_progress=bonus["currentProgress"],
2359                    daily_progress=bonus["dailyProgress"],
2360                    needed=bonus["progressToNextLevel"],
2361                    next_level=bonus["nextLevelAt"],
2362                )
2363            artifact = season.Artifact(
2364                net=self._net,
2365                hash=raw_artifact["artifactHash"],
2366                power_bonus=raw_artifact["powerBonus"],
2367                acquired_points=raw_artifact["pointsAcquired"],
2368                bonus=power_bonus_prog,
2369                points=points_prog,
2370            )
2371        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2373    def deserialize_profile_progression(
2374        self, payload: typedefs.JSONObject
2375    ) -> profile.ProfileProgression:
2376        return profile.ProfileProgression(
2377            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2378            checklist={
2379                int(check_id): checklists
2380                for check_id, checklists in payload["data"]["checklists"].items()
2381            },
2382        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2384    def deserialize_instanced_item(
2385        self, payload: typedefs.JSONObject
2386    ) -> items.ItemInstance:
2387        damage_type_hash: typing.Optional[int] = None
2388        if raw_damagetype_hash := payload.get("damageTypeHash"):
2389            damage_type_hash = int(raw_damagetype_hash)
2390
2391        required_hashes: typing.Optional[collections.Collection[int]] = None
2392        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2393            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2394
2395        breaker_type: typing.Optional[items.ItemBreakerType] = None
2396        if raw_break_type := payload.get("breakerType"):
2397            breaker_type = items.ItemBreakerType(int(raw_break_type))
2398
2399        breaker_type_hash: typing.Optional[int] = None
2400        if raw_break_type_hash := payload.get("breakerTypeHash"):
2401            breaker_type_hash = int(raw_break_type_hash)
2402
2403        energy: typing.Optional[items.ItemEnergy] = None
2404        if raw_energy := payload.get("energy"):
2405            energy = self.deserialize_item_energy(raw_energy)
2406
2407        primary_stats = None
2408        if raw_primary_stats := payload.get("primaryStat"):
2409            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2410
2411        return items.ItemInstance(
2412            damage_type=enums.DamageType(int(payload["damageType"])),
2413            damage_type_hash=damage_type_hash,
2414            primary_stat=primary_stats,
2415            item_level=int(payload["itemLevel"]),
2416            quality=int(payload["quality"]),
2417            is_equipped=payload["isEquipped"],
2418            can_equip=payload["canEquip"],
2419            equip_required_level=int(payload["equipRequiredLevel"]),
2420            required_equip_unlock_hashes=required_hashes,
2421            cant_equip_reason=int(payload["cannotEquipReason"]),
2422            breaker_type=breaker_type,
2423            breaker_type_hash=breaker_type_hash,
2424            energy=energy,
2425        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2427    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2428        energy_hash: typing.Optional[int] = None
2429        if raw_energy_hash := payload.get("energyTypeHash"):
2430            energy_hash = int(raw_energy_hash)
2431
2432        return items.ItemEnergy(
2433            hash=energy_hash,
2434            type=items.ItemEnergyType(int(payload["energyType"])),
2435            capacity=int(payload["energyCapacity"]),
2436            used_energy=int(payload["energyUsed"]),
2437            unused_energy=int(payload["energyUnused"]),
2438        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2440    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2441        perk_hash: typing.Optional[int] = None
2442        if raw_perk_hash := payload.get("perkHash"):
2443            perk_hash = int(raw_perk_hash)
2444
2445        return items.ItemPerk(
2446            hash=perk_hash,
2447            icon=assets.Image(payload["iconPath"]),
2448            is_active=payload["isActive"],
2449            is_visible=payload["visible"],
2450        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2452    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2453        plug_hash: typing.Optional[int] = None
2454        if raw_plug_hash := payload.get("plugHash"):
2455            plug_hash = int(raw_plug_hash)
2456
2457        enable_fail_indexes: typing.Optional[list[int]] = None
2458        if raw_indexes := payload.get("enableFailIndexes"):
2459            enable_fail_indexes = [int(index) for index in raw_indexes]
2460
2461        return items.ItemSocket(
2462            plug_hash=plug_hash,
2463            is_enabled=payload["isEnabled"],
2464            enable_fail_indexes=enable_fail_indexes,
2465            is_visible=payload.get("visible"),
2466        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2468    def deserialize_item_stats_view(
2469        self, payload: typedefs.JSONObject
2470    ) -> items.ItemStatsView:
2471        return items.ItemStatsView(
2472            stat_hash=payload.get("statHash"), value=payload.get("value")
2473        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2475    def deserialize_plug_item_state(
2476        self, payload: typedefs.JSONObject
2477    ) -> items.PlugItemState:
2478        item_hash: typing.Optional[int] = None
2479        if raw_item_hash := payload.get("plugItemHash"):
2480            item_hash = int(raw_item_hash)
2481
2482        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2483        if raw_fail_indexes := payload.get("insertFailIndexes"):
2484            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2485
2486        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2487        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2488            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2489
2490        return items.PlugItemState(
2491            item_hash=item_hash,
2492            insert_fail_indexes=insert_fail_indexes,
2493            enable_fail_indexes=enable_fail_indexes,
2494            is_enabled=payload["enabled"],
2495            can_insert=payload["canInsert"],
2496        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 67@typing.final
 68class FireteamActivity(int, enums.Enum):
 69    """An enum for the fireteam activities."""
 70
 71    ALL = 0
 72    CRUCIBLE = 2
 73    TRIALS_OF_OSIRIS = 3
 74    NIGHTFALL = 4
 75    ANY = 5
 76    GAMBIT = 6
 77    BLIND_WELL = 7
 78    NIGHTMARE_HUNTS = 12
 79    ALTARS_OF_SORROWS = 14
 80    DUNGEON = 15
 81    RAID_LW = 20
 82    RAID_GOS = 21
 83    RAID_DSC = 22
 84    EXO_CHALLENGE = 23
 85    S12_WRATHBORN = 24
 86    EMPIRE_HUNTS = 25
 87    S13_BATTLEGROUNDS = 26
 88    EXOTIC_QUEST = 27
 89    RAID_VOG = 28
 90    S14_EXPUNGE = 30
 91    S15_ASTRAL_ALIGNMENT = 31
 92    S15_SHATTERED_RELAM = 32
 93    SHATTERED_THRONE = 33
 94    PROPHECY = 34
 95    PIT_OF_HERESY = 35
 96    DOE = 36
 97    """Dares of Eternity."""
 98    DUNGEON_GOA = 37
 99    """Grasp of Avarice."""
100    VOW_OF_THE_DISCPILE = 38
101    CAMPAIGN = 39
102    WELLSPRING = 40
103    S16_BATTLEGROUNDS = 41
104    S17_NIGHTMARE_CONTAINMENT = 44
105    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
131@typing.final
132class FireteamDate(int, enums.Enum):
133    """An enum for fireteam date ranges."""
134
135    ALL = 0
136    NOW = 1
137    TODAY = 2
138    TWO_DAYS = 3
139    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
108@typing.final
109class FireteamLanguage(str, enums.Enum):
110    """An enum for fireteams languages filters."""
111
112    ALL = ""
113    ENGLISH = "en"
114    FRENCH = "fr"
115    ESPANOL = "es"
116    DEUTSCH = "de"
117    ITALIAN = "it"
118    JAPANESE = "ja"
119    PORTUGUESE = "pt-br"
120    RUSSIAN = "ru"
121    POLISH = "pl"
122    KOREAN = "ko"
123    # ? China
124    ZH_CHT = "zh-cht"
125    ZH_CHS = "zh-chs"
126
127    def __str__(self) -> str:
128        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
54@typing.final
55class FireteamPlatform(int, enums.Enum):
56    """An enum for fireteam related to bungie fireteams.
57    This is different from the normal `aiobungie.MembershipType`.
58    """
59
60    ANY = 0
61    PSN_NETWORK = 1
62    XBOX_LIVE = 2
63    STEAM = 4
64    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
 97class Flag(__enum.Flag):
 98    """Builtin Python enum flag with extra handlings."""
 99
100    # Needs to type this here for mypy
101    _value_: int
102
103    @property
104    def name(self) -> str:  # type: ignore[override]
105        if self._name_ is None:
106            self._name_ = f"UNKNOWN {self._value_}"
107
108        return self._name_
109
110    @property
111    def value(self) -> int:  # type: ignore[override]
112        return self._value_
113
114    def __str__(self) -> str:
115        return self.name
116
117    def __repr__(self) -> str:
118        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
119
120    def __int__(self) -> int:
121        if isinstance(self.value, _ITERABLE):
122            raise TypeError(
123                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
124            )
125        return int(self.value)
126
127    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
128        return self.__class__(self._value_ | int(other))
129
130    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
131        return self.__class__(self._value_ ^ int(other))
132
133    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
134        return self.__class__(other & int(other))
135
136    def __invert__(self) -> Flag:
137        return self.__class__(~self._value_)
138
139    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
140        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str

The name of the Enum member.

value: int

The value of the Enum member.

@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
120@attrs.define(auto_exc=True)
121class Forbidden(HTTPException):
122    """Exception that's raised for when status code 403 occurs."""
123
124    http_status: http.HTTPStatus = attrs.field(
125        default=http.HTTPStatus.FORBIDDEN, init=False
126    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
269@typing.final
270class GameMode(int, Enum):
271    """An Enum for all available gamemodes in Destiny 2."""
272
273    NONE = 0
274    STORY = 2
275    STRIKE = 3
276    RAID = 4
277    ALLPVP = 5
278    PATROL = 6
279    ALLPVE = 7
280    RESERVED9 = 9
281    CONTROL = 10
282    RESERVED11 = 11
283    CLASH = 12
284    RESERVED13 = 13
285    CRIMSONDOUBLES = 15
286    NIGHTFALL = 16
287    HEROICNIGHTFALL = 17
288    ALLSTRIKES = 18
289    IRONBANNER = 19
290    RESERVED20 = 20
291    RESERVED21 = 21
292    RESERVED22 = 22
293    RESERVED24 = 24
294    ALLMAYHEM = 25
295    RESERVED26 = 26
296    RESERVED27 = 27
297    RESERVED28 = 28
298    RESERVED29 = 29
299    RESERVED30 = 30
300    SUPREMACY = 31
301    PRIVATEMATCHESALL = 32
302    SURVIVAL = 37
303    COUNTDOWN = 38
304    TRIALSOFTHENINE = 39
305    SOCIAL = 40
306    TRIALSCOUNTDOWN = 41
307    TRIALSSURVIVAL = 42
308    IRONBANNERCONTROL = 43
309    IRONBANNERCLASH = 44
310    IRONBANNERSUPREMACY = 45
311    SCOREDNIGHTFALL = 46
312    SCOREDHEROICNIGHTFALL = 47
313    RUMBLE = 48
314    ALLDOUBLES = 49
315    DOUBLES = 50
316    PRIVATEMATCHESCLASH = 51
317    PRIVATEMATCHESCONTROL = 52
318    PRIVATEMATCHESSUPREMACY = 53
319    PRIVATEMATCHESCOUNTDOWN = 54
320    PRIVATEMATCHESSURVIVAL = 55
321    PRIVATEMATCHESMAYHEM = 56
322    PRIVATEMATCHESRUMBLE = 57
323    HEROICADVENTURE = 58
324    SHOWDOWN = 59
325    LOCKDOWN = 60
326    SCORCHED = 61
327    SCORCHEDTEAM = 62
328    GAMBIT = 63
329    ALLPVECOMPETITIVE = 64
330    BREAKTHROUGH = 65
331    BLACKARMORYRUN = 66
332    SALVAGE = 67
333    IRONBANNERSALVAGE = 68
334    PVPCOMPETITIVE = 69
335    PVPQUICKPLAY = 70
336    CLASHQUICKPLAY = 71
337    CLASHCOMPETITIVE = 72
338    CONTROLQUICKPLAY = 73
339    CONTROLCOMPETITIVE = 74
340    GAMBITPRIME = 75
341    RECKONING = 76
342    MENAGERIE = 77
343    VEXOFFENSIVE = 78
344    NIGHTMAREHUNT = 79
345    ELIMINATION = 80
346    MOMENTUM = 81
347    DUNGEON = 82
348    SUNDIAL = 83
349    TRIALS_OF_OSIRIS = 84
350    DARES = 85
351    OFFENSIVE = 86
352    LOSTSECTOR = 87
353    RIFT = 88
354    ZONECONTROL = 89
355    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
484@typing.final
485class Gender(int, Enum):
486    """An Enum for Destiny Genders."""
487
488    MALE = 0
489    FEMALE = 1
490    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
653@typing.final
654class GroupType(int, Enum):
655    """An enums for the known bungie group types."""
656
657    GENERAL = 0
658    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
62@attrs.define(auto_exc=True)
63class HTTPError(AiobungieError):
64    """Exception base used for HTTP request errors."""
65
66    message: str
67    """The error message."""
68
69    http_status: http.HTTPStatus
70    """The response status."""

Exception base used for HTTP request errors.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 73@attrs.define(auto_exc=True, kw_only=True)
 74class HTTPException(HTTPError):
 75    """Exception base internally used for an HTTP request response errors."""
 76
 77    error_code: int
 78    """The returned Bungie error status code."""
 79
 80    http_status: http.HTTPStatus
 81    """The request response http status."""
 82
 83    throttle_seconds: int
 84    """The Bungie response throttle seconds."""
 85
 86    url: typing.Optional[typedefs.StrOrURL]
 87    """The URL/endpoint caused this error."""
 88
 89    body: typing.Any
 90    """The response body."""
 91
 92    headers: multidict.CIMultiDictProxy[str]
 93    """The response headers."""
 94
 95    message: str
 96    """A Bungie human readable message describes the cause of the error."""
 97
 98    error_status: str
 99    """A Bungie short error status describes the cause of the error."""
100
101    message_data: dict[str, str]
102    """A dict of string key, value that includes each cause of the error
103    to a message describes information about that error.
104    """
105
106    def __str__(self) -> str:
107        if self.message:
108            message_body = self.message
109
110        if self.error_status:
111            error_status_body = self.error_status
112
113        return (
114            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
115            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
116            f"{str(self.body)}"
117        )

Exception base internally used for an HTTP request response errors.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
class Image:
 72class Image:
 73    """Representation of an image/avatar/picture at Bungie.
 74
 75    Example
 76    -------
 77    ```py
 78    from aiobungie import Image
 79    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 80    print(img)
 81    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 82
 83    # Stream the image.
 84    async for chunk in img:
 85        # Byte chunks of the image.
 86        print(chunk)
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image. If `None`, the default missing image path will be used.
 96    """
 97
 98    __slots__ = ("_path",)
 99
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
102
103    @property
104    def is_missing(self) -> bool:
105        return not self._path
106
107    @property
108    def url(self) -> str:
109        """The URL to the image."""
110        return self.create_url()
111
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"
116
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
126
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err
181
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader
204
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk
224
225    def __repr__(self) -> str:
226        return f"Image(url={self.create_url()})"
227
228    def __str__(self) -> str:
229        return self.create_url()
230
231    def __aiter__(self) -> Image:
232        return self
233
234    async def __anext__(self) -> bytes:
235        return await self.read()
236
237    def __await__(self) -> collections.Generator[None, None, bytes]:
238        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
190@attrs.define(auto_exc=True)
191class InternalServerError(HTTPException):
192    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
719@typing.final
720class ItemBindStatus(int, Enum):
721    """An enum for Destiny 2 items bind status."""
722
723    NOT_BOUND = 0
724    BOUND_TO_CHARACTER = 1
725    BOUND_TO_ACCOUNT = 2
726    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
729@typing.final
730class ItemLocation(int, Enum):
731    """An enum for Destiny 2 items location."""
732
733    UNKNOWN = 0
734    INVENTORY = 1
735    VAULT = 2
736    VENDOR = 3
737    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
754@typing.final
755class ItemState(Flag):
756    """An enum for Destiny 2 item states."""
757
758    NONE = 0
759    LOCKED = 1 << 0
760    TRACKED = 1 << 1
761    MASTERWORKED = 1 << 2
762    CRAFTED = 1 << 3
763    """If this bit is set, the item has been 'crafted' by the player."""
764    HIGHLITED_OBJECTIVE = 1 << 4
765    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
586@typing.final
587class ItemSubType(int, Enum):
588    """An enum for Destiny 2 inventory items subtype."""
589
590    NONE = 0
591    AUTORIFLE = 6
592    SHOTGUN = 7
593    MACHINEGUN = 8
594    HANDCANNON = 9
595    ROCKETLAUNCHER = 10
596    FUSIONRIFLE = 11
597    SNIPERRIFLE = 12
598    PULSERIFLE = 13
599    SCOUTRIFLE = 14
600    SIDEARM = 17
601    SWORD = 18
602    MASK = 19
603    SHADER = 20
604    ORNAMENT = 21
605    FUSIONRIFLELINE = 22
606    GRENADELAUNCHER = 23
607    SUBMACHINEGUN = 24
608    TRACERIFLE = 25
609    HELMETARMOR = 26
610    GAUNTLETSARMOR = 27
611    CHESTARMOR = 28
612    LEGARMOR = 29
613    CLASSARMOR = 30
614    BOW = 31
615    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
618@typing.final
619class ItemTier(int, Enum):
620    """An enum for a Destiny 2 item tier."""
621
622    NONE = 0
623    BASIC = 3340296461
624    COMMON = 2395677314
625    RARE = 2127292149
626    LEGENDERY = 4008398120
627    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
553@typing.final
554class ItemType(int, Enum):
555    """Enums for Destiny2's item types."""
556
557    NONE = 0
558    CURRENCY = 1
559    ARMOR = 2
560    WEAPON = 3
561    MESSAGE = 7
562    ENGRAM = 8
563    CONSUMABLE = 9
564    EXCHANGEMATERIAL = 10
565    MISSIONREWARD = 11
566    QUESTSTEP = 12
567    QUESTSTEPCOMPLETE = 13
568    EMBLEM = 14
569    QUEST = 15
570    SUBCLASS = 16
571    CLANBANNER = 17
572    AURA = 18
573    MOD = 19
574    DUMMY = 20
575    SHIP = 21
576    VEHICLE = 22
577    EMOTE = 23
578    GHOST = 24
579    PACKAGE = 25
580    BOUNTY = 26
581    WRAPPER = 27
582    SEASONALARTIFACT = 28
583    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Iterator(typing.Generic[~Item]):
 45class Iterator(typing.Generic[Item]):
 46    """A Flat, In-Memory iterator for sequenced based data.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = Iterator([1, 2, 3])
 52
 53    # Map the results.
 54    for item in iterator.map(lambda item: item * 2):
 55        print(item)
 56    # 2
 57    # 4
 58
 59    # Indexing is also supported.
 60    print(iterator[0])
 61    # 1
 62
 63    # Normal iteration.
 64    for item in iterator:
 65        print(item)
 66    # 1
 67    # 2
 68    # 3
 69
 70    # Union two iterators.
 71    iterator2 = Iterator([4, 5, 6])
 72    final = iterator | iterator2
 73    # <Iterator([1, 2, 3, 4, 5, 6])>
 74    ```
 75
 76    Parameters
 77    ----------
 78    items: `collections.Iterable[Item]`
 79        The items to iterate over.
 80    """
 81
 82    __slots__ = ("_items",)
 83
 84    def __init__(self, items: collections.Iterable[Item]) -> None:
 85        self._items = iter(items)
 86
 87    @typing.overload
 88    def collect(self) -> list[Item]:
 89        ...
 90
 91    @typing.overload
 92    def collect(self, casting: _B) -> list[_B]:
 93        ...
 94
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)
120
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()
143
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))
173
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))
197
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))
222
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))
247
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))
260
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))
273
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))
298
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)
323
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)
347
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))
377
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()
395
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))
413
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count
430
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))
454
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)
475
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))
501
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))
522
523    def _ok(self) -> typing.NoReturn:
524        raise StopIteration("No more items in the iterator.") from None
525
526    def __getitem__(self, index: int) -> Item:
527        try:
528            return self.skip(index).first()
529        except IndexError:
530            self._ok()
531
532    def __or__(self, other: Iterator[Item]) -> Iterator[Item]:
533        return self.union(other)
534
535    # This is a never.
536    def __setitem__(self) -> typing.NoReturn:
537        raise TypeError(
538            f"{type(self).__name__} doesn't support item assignment."
539        ) from None
540
541    def __repr__(self) -> str:
542        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
543
544    def __len__(self) -> int:
545        return self.count()
546
547    def __iter__(self) -> Iterator[Item]:
548        return self
549
550    def __next__(self) -> Item:
551        try:
552            item = next(self._items)
553        except StopIteration:
554            self._ok()
555
556        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = Iterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
Iterator(items: collections.abc.Iterable[~Item])
84    def __init__(self, items: collections.Iterable[Item]) -> None:
85        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
 95    def collect(
 96        self, casting: typing.Optional[_B] = None
 97    ) -> typing.Union[list[Item], list[_B]]:
 98        """Collects all items in the iterator into a list and cast them into an object if provided.
 99
100        Example
101        -------
102        >>> iterator = Iterator([1, 2, 3])
103        >>> iterator.collect(casting=str)
104        ["1", "2", "3"]
105
106        Parameters
107        ----------
108        casting: `T | None`
109            The type to cast the items to. If `None` is provided, the items will be returned as is.
110
111        Raises
112        ------
113        `StopIteration`
114            If no elements are left in the iterator.
115        """
116        if casting is not None:
117            return typing.cast(list[_B], list(map(casting, self._items)))
118
119        return list(self._items)

Collects all items in the iterator into a list and cast them into an object if provided.

Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
121    def next(self) -> Item:
122        """Returns the next item in the iterator.
123
124        Example
125        -------
126        ```py
127        iterator = Iterator(["1", "2", "3"])
128        item = iterator.next()
129        assert item == "1"
130        item = iterator.next()
131        assert item == "2"
132        ```
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        try:
140            return self.__next__()
141        except StopIteration:
142            self._ok()

Returns the next item in the iterator.

Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'Iterator[OtherItem]':
144    def map(
145        self, predicate: collections.Callable[[Item], OtherItem]
146    ) -> Iterator[OtherItem]:
147        """Maps each item in the iterator to its predicated value.
148
149        Example
150        -------
151        ```py
152        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
153        print(iterator)
154        # <Iterator([1, 2, 3])>
155        ```
156
157        Parameters
158        ----------
159        predicate: `collections.Callable[[Item], OtherItem]`
160            The function to map each item in the iterator to its predicated value.
161
162        Returns
163        -------
164        `Iterator[OtherItem]`
165            The mapped iterator.
166
167        Raises
168        ------
169        `StopIteration`
170            If no elements are left in the iterator.
171        """
172        return Iterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • Iterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> aiobungie.Iterator[~Item]:
174    def take(self, n: int) -> Iterator[Item]:
175        """Take the first number of items until the number of items are yielded or
176        the end of the iterator is reached.
177
178        Example
179        -------
180        ```py
181        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
182        print(iterator.take(2))
183        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
184        ```
185
186        Parameters
187        ----------
188        n: `int`
189            The number of items to take.
190
191        Raises
192        ------
193        `StopIteration`
194            If no elements are left in the iterator.
195        """
196        return Iterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
198    def take_while(
199        self, predicate: collections.Callable[[Item], bool]
200    ) -> Iterator[Item]:
201        """Yields items from the iterator while predicate returns `True`.
202
203        Example
204        -------
205        ```py
206        iterator = Iterator([STEAM, XBOX, STADIA])
207        print(iterator.take_while(lambda platform: platform is not XBOX))
208        # <Iterator([STEAM])>
209        ```
210
211        Parameters
212        ----------
213        predicate: `collections.Callable[[Item], bool]`
214            The function to predicate each item in the iterator.
215
216        Raises
217        ------
218        `StopIteration`
219            If no elements are left in the iterator.
220        """
221        return Iterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
223    def drop_while(
224        self, predicate: collections.Callable[[Item], bool]
225    ) -> Iterator[Item]:
226        """Yields items from the iterator while predicate returns `False`.
227
228        Example
229        -------
230        ```py
231        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
232        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
233        # <Iterator([DestinyMembership(name="Bob")])>
234        ```
235
236        Parameters
237        ----------
238        predicate: `collections.Callable[[Item], bool]`
239            The function to predicate each item in the iterator.
240
241        Raises
242        ------
243        `StopIteration`
244            If no elements are left in the iterator.
245        """
246        return Iterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.Iterator[~Item]:
248    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
249        """Filters the iterator to only yield items that match the predicate.
250
251        Example
252        -------
253        ```py
254        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
255        print(names.filter(lambda n: n != "Jim"))
256        # <Iterator(["Bob", "Mike", "Jess"])>
257        ```
258        """
259        return Iterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> aiobungie.Iterator[~Item]:
261    def skip(self, n: int) -> Iterator[Item]:
262        """Skips the first number of items in the iterator.
263
264        Example
265        -------
266        ```py
267        iterator = Iterator([STEAM, XBOX, STADIA])
268        print(iterator.skip(1))
269        # <Iterator([XBOX, STADIA])>
270        ```
271        """
272        return Iterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
def zip(self, other: 'Iterator[OtherItem]') -> 'Iterator[tuple[Item, OtherItem]]':
274    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
275        """Zips the iterator with another iterable.
276
277        Example
278        -------
279        ```py
280        iterator = Iterator([1, 3, 5])
281        other = Iterator([2, 4, 6])
282        for item, other_item in iterator.zip(other):
283            print(item, other_item)
284        # <Iterator([(1, 2), (3, 4), (5, 6)])>
285        ```
286
287        Parameters
288        ----------
289        other: `Iterator[OtherItem]`
290            The iterable to zip with.
291
292        Raises
293        ------
294        `StopIteration`
295            If no elements are left in the iterator.
296        """
297        return Iterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (Iterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
299    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
300        """`True` if all items in the iterator match the predicate.
301
302        Example
303        -------
304        ```py
305        iterator = Iterator([1, 2, 3])
306        while iterator.all(lambda item: isinstance(item, int)):
307            print("Still all integers")
308            continue
309        # Still all integers
310        ```
311
312        Parameters
313        ----------
314        predicate: `collections.Callable[[Item], bool]`
315            The function to test each item in the iterator.
316
317        Raises
318        ------
319        `StopIteration`
320            If no elements are left in the iterator.
321        """
322        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
324    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
325        """`True` if any items in the iterator match the predicate.
326
327        Example
328        -------
329        ```py
330        iterator = Iterator([1, 2, 3])
331        if iterator.any(lambda item: isinstance(item, int)):
332            print("At least one item is an int.")
333        # At least one item is an int.
334        ```
335
336        Parameters
337        ----------
338        predicate: `collections.Callable[[Item], bool]`
339            The function to test each item in the iterator.
340
341        Raises
342        ------
343        `StopIteration`
344            If no elements are left in the iterator.
345        """
346        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> aiobungie.Iterator[~Item]:
348    def sort(
349        self,
350        *,
351        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
352        reverse: bool = False,
353    ) -> Iterator[Item]:
354        """Sorts the iterator.
355
356        Example
357        -------
358        ```py
359        iterator = Iterator([3, 1, 6, 7])
360        print(iterator.sort(key=lambda item: item))
361        # <Iterator([1, 3, 6, 7])>
362        ```
363
364        Parameters
365        ----------
366        key: `collections.Callable[[Item], Any]`
367            The function to sort by.
368        reverse: `bool`
369            Whether to reverse the sort.
370
371        Raises
372        ------
373        `StopIteration`
374            If no elements are left in the iterator.
375        """
376        return Iterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
378    def first(self) -> Item:
379        """Returns the first item in the iterator.
380
381        Example
382        -------
383        ```py
384        iterator = Iterator([3, 1, 6, 7])
385        print(iterator.first())
386        3
387        ```
388
389        Raises
390        ------
391        `StopIteration`
392            If no elements are left in the iterator.
393        """
394        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> aiobungie.Iterator[~Item]:
396    def reversed(self) -> Iterator[Item]:
397        """Returns a new iterator that yields the items in the iterator in reverse order.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.reversed())
404        # <Iterator([7, 6, 1, 3])>
405        ```
406
407        Raises
408        ------
409        `StopIteration`
410            If no elements are left in the iterator.
411        """
412        return Iterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
414    def count(self) -> int:
415        """Returns the number of items in the iterator.
416
417        Example
418        -------
419        ```py
420        iterator = Iterator([3, 1, 6, 7])
421        print(iterator.count())
422        4
423        ```
424        """
425        count = 0
426        for _ in self:
427            count += 1
428
429        return count

Returns the number of items in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: aiobungie.Iterator[~Item]) -> aiobungie.Iterator[~Item]:
431    def union(self, other: Iterator[Item]) -> Iterator[Item]:
432        """Returns a new iterator that yields all items from both iterators.
433
434        Example
435        -------
436        ```py
437        iterator = Iterator([1, 2, 3])
438        other = Iterator([4, 5, 6])
439        print(iterator.union(other))
440        # <Iterator([1, 2, 3, 4, 5, 6])>
441        ```
442
443        Parameters
444        ----------
445        other: `Iterator[Item]`
446            The iterable to union with.
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return Iterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (Iterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
455    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
456        """Calls the function on each item in the iterator.
457
458        Example
459        -------
460        ```py
461        iterator = Iterator([1, 2, 3])
462        iterator.for_each(lambda item: print(item))
463        # 1
464        # 2
465        # 3
466        ```
467
468        Parameters
469        ----------
470        func: `typeshed.Callable[[Item], None]`
471            The function to call on each item in the iterator.
472        """
473        for item in self:
474            func(item)

Calls the function on each item in the iterator.

Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
476    async def async_for_each(
477        self,
478        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
479    ) -> None:
480        """Calls the async function on each item in the iterator concurrently.
481
482        Example
483        -------
484        ```py
485        async def signup(username: str) -> None:
486            async with aiohttp.request('POST', '...') as r:
487                # Actual logic.
488                ...
489
490        async def main():
491            users = aiobungie.into_iter(["user_danny", "user_jojo"])
492            await users.async_for_each(lambda username: signup(username))
493        ```
494
495        Parameters
496        ----------
497        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
498            The async function to call on each item in the iterator.
499        """
500        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> aiobungie.Iterator[tuple[int, ~Item]]:
502    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
503        """Returns a new iterator that yields tuples of the index and item.
504
505        Example
506        -------
507        ```py
508        iterator = Iterator([1, 2, 3])
509        for index, item in iterator.enumerate():
510            print(index, item)
511        # 0 1
512        # 1 2
513        # 2 3
514        ```
515
516        Raises
517        ------
518        `StopIteration`
519            If no elements are left in the iterator.
520        """
521        return Iterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
710@typing.final
711class MembershipOption(int, Enum):
712    """A enum for GroupV2 membership options."""
713
714    REVIEWD = 0
715    OPEN = 1
716    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
458@typing.final
459class MembershipType(int, Enum):
460    """An Enum for Bungie membership types."""
461
462    NONE = 0
463    XBOX = 1
464    PSN = 2
465    STEAM = 3
466    BLIZZARD = 4
467    STADIA = 5
468    EPIC_GAMES_STORE = 6
469    DEMON = 10
470    BUNGIE = 254
471    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
EPIC_GAMES_STORE = <MembershipType.EPIC_GAMES_STORE: 6>
DEMON = <MembershipType.DEMON: 10>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
163@attrs.define(auto_exc=True)
164class MembershipTypeError(BadRequest):
165    """A bad request error raised when passing wrong membership to the request.
166
167    Those fields are useful since it returns the correct membership and id which can be used
168    to make the request again with those fields.
169    """
170
171    membership_type: str = attrs.field(default="")
172    """The errored membership type passed to the request."""
173
174    membership_id: int = attrs.field(default=0)
175    """The errored user's membership id."""
176
177    required_membership: str = attrs.field(default="")
178    """The required correct membership for errored user."""
179
180    def __str__(self) -> str:
181        return (
182            f"Expected membership: {self.required_membership}, "
183            f"But got {self.membership_type} for id {self.membership_id}"
184        )
185
186    def __int__(self) -> int:
187        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>, membership_type: str = '', membership_id: int = 0, required_membership: str = '')
 2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = http_status
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
503@typing.final
504class MilestoneType(int, Enum):
505    """An Enum for Destiny 2 milestone types."""
506
507    UNKNOWN = 0
508    TUTORIAL = 1
509    ONETIME = 2
510    WEEKLY = 3
511    DAILY = 4
512    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
129@attrs.define(auto_exc=True)
130class NotFound(HTTPException):
131    """Raised when an unknown request was not found."""
132
133    http_status: http.HTTPStatus = attrs.field(
134        default=http.HTTPStatus.NOT_FOUND, init=False
135    )

Raised when an unknown request was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
230@typing.final
231class Place(int, Enum):
232    """An Enum for Destiny 2 Places and NOT Planets"""
233
234    ORBIT = 2961497387
235    SOCIAL = 4151112093
236    LIGHT_HOUSE = 4276116472
237    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
195@typing.final
196class Planet(int, Enum):
197    """An Enum for all available planets in Destiny 2."""
198
199    UNKNOWN = 0
200    """Unknown space"""
201
202    EARTH = 3747705955
203    """Earth"""
204
205    DREAMING_CITY = 2877881518
206    """The Dreaming city."""
207
208    NESSUS = 3526908984
209    """Nessus"""
210
211    MOON = 3325508439
212    """The Moon"""
213
214    COSMODROME = 3990611421
215    """The Cosmodrome"""
216
217    TANGLED_SHORE = 3821439926
218    """The Tangled Shore"""
219
220    VENUS = 3871070152
221    """Venus"""
222
223    EAZ = 541863059  # Exclusive event.
224    """European Aerial Zone"""
225
226    EUROPA = 1729879943
227    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
680@typing.final
681class Presence(int, Enum):
682    """An enum for a bungie friend status."""
683
684    OFFLINE_OR_UNKNOWN = 0
685    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
768@typing.final
769class PrivacySetting(int, Enum):
770    """An enum for players's privacy settings."""
771
772    OPEN = 0
773    CLAN_AND_FRIENDS = 1
774    FRIENDS_ONLY = 2
775    INVITE_ONLY = 3
776    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 351class RESTClient(interfaces.RESTInterface):
 352    """A RESTful client implementation for Bungie's API.
 353
 354    This client is designed to only make HTTP requests and return JSON objects
 355    to provide RESTful functionality.
 356
 357    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 358    using the factory into Pythonic data classes objects which provide Python functionality.
 359
 360    Example
 361    -------
 362    ```py
 363    import aiobungie
 364
 365    async def main():
 366        async with aiobungie.RESTClient("TOKEN") as rest_client:
 367            req = await rest_client.fetch_clan_members(4389205)
 368            clan_members = req['results']
 369            for member in clan_members:
 370                for k, v in member['destinyUserInfo'].items():
 371                    print(k, v)
 372    ```
 373
 374    Parameters
 375    ----------
 376    token : `str`
 377        A valid application token from Bungie's developer portal.
 378
 379    Other Parameters
 380    ----------------
 381    max_retries : `int`
 382        The max retries number to retry if the request hit a `5xx` status code.
 383    client_secret : `typing.Optional[str]`
 384        An optional application client secret,
 385        This is only needed if you're fetching OAuth2 tokens with this client.
 386    client_id : `typing.Optional[int]`
 387        An optional application client id,
 388        This is only needed if you're fetching OAuth2 tokens with this client.
 389    enable_debugging : `bool | str`
 390        Whether to enable logging responses or not.
 391
 392    Logging Levels
 393    --------------
 394    * `False`: This will disable logging.
 395    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 396    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 397    """
 398
 399    __slots__ = (
 400        "_token",
 401        "_session",
 402        "_lock",
 403        "_max_retries",
 404        "_client_secret",
 405        "_client_id",
 406        "_metadata",
 407    )
 408
 409    def __init__(
 410        self,
 411        token: str,
 412        /,
 413        client_secret: typing.Optional[str] = None,
 414        client_id: typing.Optional[int] = None,
 415        *,
 416        max_retries: int = 4,
 417        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 418    ) -> None:
 419        self._session: typing.Optional[_Session] = None
 420        self._lock: typing.Optional[asyncio.Lock] = None
 421        self._client_secret = client_secret
 422        self._client_id = client_id
 423        self._token: str = token
 424        self._max_retries = max_retries
 425        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 426
 427        self._set_debug_level(enable_debugging)
 428
 429    @property
 430    def client_id(self) -> typing.Optional[int]:
 431        return self._client_id
 432
 433    @property
 434    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 435        return self._metadata
 436
 437    @property
 438    def is_alive(self) -> bool:
 439        return self._session is not None
 440
 441    @typing.final
 442    async def close(self) -> None:
 443        session = self._get_session()
 444        await session.close()
 445        self._session = None
 446
 447    @typing.final
 448    def open(self) -> None:
 449        """Open a new client session. This is called internally with contextmanager usage."""
 450        if self.is_alive:
 451            raise RuntimeError("Cannot open a new session while it's already open.")
 452
 453        self._session = _Session.create(owner=False, raise_status=False)
 454
 455    @typing.final
 456    def enable_debugging(
 457        self,
 458        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 459        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 460        /,
 461    ) -> None:
 462        self._set_debug_level(level, file)
 463
 464    @typing.final
 465    async def static_request(
 466        self,
 467        method: typing.Union[RequestMethod, str],
 468        path: str,
 469        *,
 470        auth: typing.Optional[str] = None,
 471        json: typing.Optional[dict[str, typing.Any]] = None,
 472    ) -> ResponseSig:
 473        return await self._request(method, path, auth=auth, json=json)
 474
 475    @typing.final
 476    def build_oauth2_url(
 477        self, client_id: typing.Optional[int] = None
 478    ) -> typing.Optional[builders.OAuthURL]:
 479        client_id = client_id or self._client_id
 480        if client_id is None:
 481            return None
 482
 483        return builders.OAuthURL(client_id=client_id)
 484
 485    @staticmethod
 486    def _set_debug_level(
 487        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 488        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 489    ) -> None:
 490
 491        file_handler = logging.FileHandler(file, mode="w") if file else None
 492        if level == "TRACE" or level == TRACE:
 493            logging.basicConfig(
 494                level=TRACE, handlers=[file_handler] if file_handler else None
 495            )
 496
 497        elif level:
 498            logging.basicConfig(
 499                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 500            )
 501
 502    def _get_session(self) -> _Session:
 503        if self._session:
 504            return self._session
 505
 506        raise RuntimeError(
 507            "Cannot return a session while its close. Make sure you use `async with` before making requests."
 508        )
 509
 510    async def _request(
 511        self,
 512        method: typing.Union[RequestMethod, str],
 513        route: str,
 514        *,
 515        base: bool = False,
 516        oauth2: bool = False,
 517        auth: typing.Optional[str] = None,
 518        unwrapping: typing.Literal["json", "read"] = "json",
 519        json: typing.Optional[dict[str, typing.Any]] = None,
 520        headers: typing.Optional[dict[str, typing.Any]] = None,
 521        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 522    ) -> ResponseSig:
 523
 524        retries: int = 0
 525        session = self._get_session()
 526        headers = headers or {}
 527
 528        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 529        headers["X-API-KEY"] = self._token
 530
 531        if auth is not None:
 532            headers[_AUTH_HEADER] = f"Bearer {auth}"
 533
 534        # Handling endpoints
 535        endpoint = url.BASE
 536
 537        if not base:
 538            endpoint = endpoint + url.REST_EP
 539
 540        if oauth2:
 541            headers["Content-Type"] = "application/x-www-form-urlencoded"
 542            endpoint = endpoint + url.TOKEN_EP
 543
 544        if self._lock is None:
 545            self._lock = asyncio.Lock()
 546
 547        while True:
 548            async with (stack := contextlib.AsyncExitStack()):
 549                await stack.enter_async_context(self._lock)
 550
 551                # We make the request here.
 552                taken_time = time.monotonic()
 553                response = await stack.enter_async_context(
 554                    session.client_session.request(
 555                        method=method,
 556                        url=f"{endpoint}/{route}",
 557                        json=json,
 558                        headers=headers,
 559                        data=data,
 560                    )
 561                )
 562                response_time = (time.monotonic() - taken_time) * 1_000
 563
 564                _LOG.debug(
 565                    "%s %s %s Time %.4fms",
 566                    method,
 567                    f"{endpoint}/{route}",
 568                    f"{response.status} {response.reason}",
 569                    response_time,
 570                )
 571
 572                await self._handle_ratelimit(response, method, route)
 573
 574                if response.status == http.HTTPStatus.NO_CONTENT:
 575                    return None
 576
 577                if 300 > response.status >= 200:
 578                    if unwrapping == "read":
 579                        # We need to read the bytes for the manifest response.
 580                        return await response.read()
 581
 582                    if response.content_type == _APP_JSON:
 583                        json_data = await response.json()
 584
 585                        _LOG.debug(
 586                            "%s %s %s Time %.4fms",
 587                            method,
 588                            f"{endpoint}/{route}",
 589                            f"{response.status} {response.reason}",
 590                            response_time,
 591                        )
 592
 593                        if _LOG.isEnabledFor(TRACE):
 594                            headers.update(response.headers)  # type: ignore
 595
 596                            _LOG.log(
 597                                TRACE,
 598                                "%s",
 599                                error.stringify_http_message(headers),
 600                            )
 601
 602                        # Return the response.
 603                        # oauth2 responses are not packed inside a Response object.
 604                        if oauth2:
 605                            return json_data  # type: ignore[no-any-return]
 606
 607                        return json_data["Response"]  # type: ignore[no-any-return]
 608
 609                if (
 610                    response.status in _RETRY_5XX
 611                    and retries < self._max_retries  # noqa: W503
 612                ):
 613                    backoff_ = backoff.ExponentialBackOff(maximum=6)
 614                    sleep_time = next(backoff_)
 615                    _LOG.warning(
 616                        "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 617                        response.status,
 618                        response.reason,
 619                        sleep_time,
 620                        self._max_retries - retries,
 621                    )
 622
 623                    retries += 1
 624                    await asyncio.sleep(sleep_time)
 625                    continue
 626
 627                raise await error.raise_error(response)
 628
 629    if not typing.TYPE_CHECKING:
 630
 631        def __enter__(self) -> typing.NoReturn:
 632            cls = type(self)
 633            raise TypeError(
 634                f"{cls.__qualname__} is async only, use 'async with' instead."
 635            )
 636
 637        def __exit__(
 638            self,
 639            exception_type: typing.Optional[type[BaseException]],
 640            exception: typing.Optional[BaseException],
 641            exception_traceback: typing.Optional[types.TracebackType],
 642        ) -> None:
 643            ...
 644
 645    async def __aenter__(self) -> RESTClient:
 646        self.open()
 647        return self
 648
 649    async def __aexit__(
 650        self,
 651        exception_type: typing.Optional[type[BaseException]],
 652        exception: typing.Optional[BaseException],
 653        exception_traceback: typing.Optional[types.TracebackType],
 654    ) -> None:
 655        await self.close()
 656
 657    # We don't want this to be super complicated.
 658    @typing.final
 659    async def _handle_ratelimit(
 660        self,
 661        response: aiohttp.ClientResponse,
 662        method: str,
 663        route: str,
 664    ) -> None:
 665
 666        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 667            return
 668
 669        if response.content_type != _APP_JSON:
 670            raise error.HTTPError(
 671                f"Being ratelimited on non JSON request, {response.content_type}.",
 672                http.HTTPStatus.TOO_MANY_REQUESTS,
 673            )
 674
 675        json: typedefs.JSONObject = await response.json()
 676        retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1
 677        max_calls: int = 0
 678
 679        while True:
 680            if max_calls == 10:
 681                # Max retries by default. We raise an error here.
 682                raise error.RateLimitedError(
 683                    body=json,
 684                    url=str(response.real_url),
 685                    retry_after=retry_after,
 686                )
 687
 688            # We sleep for a little bit to avoid funky behavior.
 689            _LOG.warning(
 690                "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.",
 691                method,
 692                route,
 693                retry_after,
 694            )
 695            await asyncio.sleep(retry_after)
 696            max_calls += 1
 697            continue
 698
 699    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 700        if not isinstance(self._client_secret, (str, int)):
 701            raise TypeError(
 702                "Expected (str, int) for client secret "
 703                f"but got {type(self._client_secret).__name__}"  # type: ignore
 704            )
 705
 706        headers = {
 707            "client_secret": self._client_secret,
 708        }
 709
 710        data = (
 711            f"grant_type=authorization_code&code={code}"
 712            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 713        )
 714
 715        response = await self._request(
 716            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 717        )
 718        assert isinstance(response, dict)
 719        return builders.OAuth2Response.build_response(response)
 720
 721    async def refresh_access_token(
 722        self, refresh_token: str, /
 723    ) -> builders.OAuth2Response:
 724        if not isinstance(self._client_secret, (int, str)):
 725            raise TypeError(
 726                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
 727            )
 728
 729        data = {
 730            "grant_type": "refresh_token",
 731            "refresh_token": refresh_token,
 732            "client_id": self._client_id,
 733            "client_secret": self._client_secret,
 734            "Content-Type": "application/x-www-form-urlencoded",
 735        }
 736
 737        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 738        assert isinstance(response, dict)
 739        return builders.OAuth2Response.build_response(response)
 740
 741    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 742        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 743        resp = await self._request(
 744            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 745        )
 746        assert isinstance(resp, dict)
 747        return resp
 748
 749    async def fetch_user_themes(self) -> typedefs.JSONArray:
 750        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 751        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 752        assert isinstance(resp, list)
 753        return resp
 754
 755    async def fetch_membership_from_id(
 756        self,
 757        id: int,
 758        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 759        /,
 760    ) -> typedefs.JSONObject:
 761        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 762        resp = await self._request(
 763            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 764        )
 765        assert isinstance(resp, dict)
 766        return resp
 767
 768    async def fetch_player(
 769        self,
 770        name: str,
 771        code: int,
 772        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 773        /,
 774    ) -> typedefs.JSONArray:
 775        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 776        resp = await self._request(
 777            RequestMethod.POST,
 778            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 779            json={"displayName": name, "displayNameCode": code},
 780        )
 781        assert isinstance(resp, list)
 782        return resp
 783
 784    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 785        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 786        resp = await self._request(
 787            RequestMethod.POST,
 788            "User/Search/GlobalName/0",
 789            json={"displayNamePrefix": name},
 790        )
 791        assert isinstance(resp, dict)
 792        return resp
 793
 794    async def fetch_clan_from_id(
 795        self, id: int, /, access_token: typing.Optional[str] = None
 796    ) -> typedefs.JSONObject:
 797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 798        resp = await self._request(
 799            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 800        )
 801        assert isinstance(resp, dict)
 802        return resp
 803
 804    async def fetch_clan(
 805        self,
 806        name: str,
 807        /,
 808        access_token: typing.Optional[str] = None,
 809        *,
 810        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 811    ) -> typedefs.JSONObject:
 812        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 813        resp = await self._request(
 814            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 815        )
 816        assert isinstance(resp, dict)
 817        return resp
 818
 819    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 820        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 821        resp = await self._request(
 822            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 823        )
 824        assert isinstance(resp, dict)
 825        return resp
 826
 827    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 828        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 829        resp = await self._request(
 830            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 831        )
 832        assert isinstance(resp, list)
 833        return resp
 834
 835    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 836        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 837        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 838        assert isinstance(resp, dict)
 839        return resp
 840
 841    async def fetch_character(
 842        self,
 843        member_id: int,
 844        membership_type: typedefs.IntAnd[enums.MembershipType],
 845        character_id: int,
 846        components: list[enums.ComponentType],
 847        auth: typing.Optional[str] = None,
 848    ) -> typedefs.JSONObject:
 849        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 850        collector = _collect_components(components)
 851        response = await self._request(
 852            RequestMethod.GET,
 853            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 854            f"Character/{character_id}/?components={collector}",
 855            auth=auth,
 856        )
 857        assert isinstance(response, dict)
 858        return response
 859
 860    async def fetch_activities(
 861        self,
 862        member_id: int,
 863        character_id: int,
 864        mode: typedefs.IntAnd[enums.GameMode],
 865        membership_type: typedefs.IntAnd[
 866            enums.MembershipType
 867        ] = enums.MembershipType.ALL,
 868        *,
 869        page: int = 0,
 870        limit: int = 1,
 871    ) -> typedefs.JSONObject:
 872        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 873        resp = await self._request(
 874            RequestMethod.GET,
 875            f"Destiny2/{int(membership_type)}/Account/"
 876            f"{member_id}/Character/{character_id}/Stats/Activities"
 877            f"/?mode={int(mode)}&count={limit}&page={page}",
 878        )
 879        assert isinstance(resp, dict)
 880        return resp
 881
 882    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 883        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 884        resp = await self._request(
 885            RequestMethod.GET,
 886            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 887        )
 888        assert isinstance(resp, dict)
 889        return resp
 890
 891    async def fetch_profile(
 892        self,
 893        membership_id: int,
 894        type: typedefs.IntAnd[enums.MembershipType],
 895        components: list[enums.ComponentType],
 896        auth: typing.Optional[str] = None,
 897    ) -> typedefs.JSONObject:
 898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 899        collector = _collect_components(components)
 900        response = await self._request(
 901            RequestMethod.GET,
 902            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 903            auth=auth,
 904        )
 905        assert isinstance(response, dict)
 906        return response
 907
 908    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 910        response = await self._request(
 911            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 912        )
 913        assert isinstance(response, dict)
 914        return response
 915
 916    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 917        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 918        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 919        assert isinstance(resp, dict)
 920        return resp
 921
 922    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 923        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 924        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 925        assert isinstance(resp, dict)
 926        return resp
 927
 928    async def fetch_groups_for_member(
 929        self,
 930        member_id: int,
 931        member_type: typedefs.IntAnd[enums.MembershipType],
 932        /,
 933        *,
 934        filter: int = 0,
 935        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 936    ) -> typedefs.JSONObject:
 937        resp = await self._request(
 938            RequestMethod.GET,
 939            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 940        )
 941        assert isinstance(resp, dict)
 942        return resp
 943
 944    async def fetch_potential_groups_for_member(
 945        self,
 946        member_id: int,
 947        member_type: typedefs.IntAnd[enums.MembershipType],
 948        /,
 949        *,
 950        filter: int = 0,
 951        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 952    ) -> typedefs.JSONObject:
 953        resp = await self._request(
 954            RequestMethod.GET,
 955            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 956        )
 957        assert isinstance(resp, dict)
 958        return resp
 959
 960    async def fetch_clan_members(
 961        self,
 962        clan_id: int,
 963        /,
 964        *,
 965        name: typing.Optional[str] = None,
 966        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 967    ) -> typedefs.JSONObject:
 968        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 969        resp = await self._request(
 970            RequestMethod.GET,
 971            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 972        )
 973        assert isinstance(resp, dict)
 974        return resp
 975
 976    async def fetch_hardlinked_credentials(
 977        self,
 978        credential: int,
 979        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 980        /,
 981    ) -> typedefs.JSONObject:
 982        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 983        resp = await self._request(
 984            RequestMethod.GET,
 985            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
 986        )
 987        assert isinstance(resp, dict)
 988        return resp
 989
 990    async def fetch_user_credentials(
 991        self, access_token: str, membership_id: int, /
 992    ) -> typedefs.JSONArray:
 993        resp = await self._request(
 994            RequestMethod.GET,
 995            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
 996            auth=access_token,
 997        )
 998        assert isinstance(resp, list)
 999        return resp
1000
1001    async def insert_socket_plug(
1002        self,
1003        action_token: str,
1004        /,
1005        instance_id: int,
1006        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1007        character_id: int,
1008        membership_type: typedefs.IntAnd[enums.MembershipType],
1009    ) -> typedefs.JSONObject:
1010
1011        if isinstance(plug, builders.PlugSocketBuilder):
1012            plug = plug.collect()
1013
1014        body = {
1015            "actionToken": action_token,
1016            "itemInstanceId": instance_id,
1017            "plug": plug,
1018            "characterId": character_id,
1019            "membershipType": int(membership_type),
1020        }
1021        resp = await self._request(
1022            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1023        )
1024        assert isinstance(resp, dict)
1025        return resp
1026
1027    async def insert_socket_plug_free(
1028        self,
1029        access_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "itemInstanceId": instance_id,
1042            "plug": plug,
1043            "characterId": character_id,
1044            "membershipType": int(membership_type),
1045        }
1046        resp = await self._request(
1047            RequestMethod.POST,
1048            "Destiny2/Actions/Items/InsertSocketPlugFree",
1049            json=body,
1050            auth=access_token,
1051        )
1052        assert isinstance(resp, dict)
1053        return resp
1054
1055    async def set_item_lock_state(
1056        self,
1057        access_token: str,
1058        state: bool,
1059        /,
1060        item_id: int,
1061        character_id: int,
1062        membership_type: typedefs.IntAnd[enums.MembershipType],
1063    ) -> int:
1064        body = {
1065            "state": state,
1066            "itemId": item_id,
1067            "characterId": character_id,
1068            "membership_type": int(membership_type),
1069        }
1070        response = await self._request(
1071            RequestMethod.POST,
1072            "Destiny2/Actions/Items/SetLockState",
1073            json=body,
1074            auth=access_token,
1075        )
1076        assert isinstance(response, int)
1077        return response
1078
1079    async def set_quest_track_state(
1080        self,
1081        access_token: str,
1082        state: bool,
1083        /,
1084        item_id: int,
1085        character_id: int,
1086        membership_type: typedefs.IntAnd[enums.MembershipType],
1087    ) -> int:
1088        body = {
1089            "state": state,
1090            "itemId": item_id,
1091            "characterId": character_id,
1092            "membership_type": int(membership_type),
1093        }
1094        response = await self._request(
1095            RequestMethod.POST,
1096            "Destiny2/Actions/Items/SetTrackedState",
1097            json=body,
1098            auth=access_token,
1099        )
1100        assert isinstance(response, int)
1101        return response
1102
1103    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1104        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1105        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1106        assert isinstance(path, dict)
1107        return path
1108
1109    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1110        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1111        _ensure_manifest_language(language)
1112
1113        content = await self.fetch_manifest_path()
1114        resp = await self._request(
1115            RequestMethod.GET,
1116            content["mobileWorldContentPaths"][language],
1117            unwrapping="read",
1118            base=True,
1119        )
1120        assert isinstance(resp, bytes)
1121        return resp
1122
1123    async def download_manifest(
1124        self,
1125        language: str = "en",
1126        name: str = "manifest",
1127        path: typing.Union[pathlib.Path, str] = ".",
1128        *,
1129        force: bool = False,
1130    ) -> None:
1131        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1132        complete_path = _get_path(name, path, sql=True)
1133
1134        if complete_path.exists() and force:
1135            if force:
1136                _LOG.info(
1137                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1138                )
1139                complete_path.unlink(missing_ok=True)
1140
1141                return await self.download_manifest(language, name, path, force=force)
1142
1143            else:
1144                raise FileExistsError(
1145                    "Manifest file already exists, "
1146                    "To force download, set the `force` parameter to `True`."
1147                )
1148
1149        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1150        data_bytes = await self.read_manifest_bytes(language)
1151        await asyncio.get_running_loop().run_in_executor(
1152            None, _write_sqlite_bytes, data_bytes, path, name
1153        )
1154
1155    async def download_json_manifest(
1156        self,
1157        file_name: str = "manifest",
1158        path: typing.Union[str, pathlib.Path] = ".",
1159        language: str = "en",
1160    ) -> None:
1161        _ensure_manifest_language(language)
1162
1163        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1164
1165        content = await self.fetch_manifest_path()
1166        json_bytes = await self._request(
1167            RequestMethod.GET,
1168            content["jsonWorldContentPaths"][language],
1169            unwrapping="read",
1170            base=True,
1171        )
1172
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_json_bytes, json_bytes, file_name, path
1175        )
1176        _LOG.info("Finished downloading manifest JSON.")
1177
1178    async def fetch_manifest_version(self) -> str:
1179        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1180
1181    async def fetch_linked_profiles(
1182        self,
1183        member_id: int,
1184        member_type: typedefs.IntAnd[enums.MembershipType],
1185        /,
1186        *,
1187        all: bool = False,
1188    ) -> typedefs.JSONObject:
1189        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1190        resp = await self._request(
1191            RequestMethod.GET,
1192            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1193        )
1194        assert isinstance(resp, dict)
1195        return resp
1196
1197    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1198        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1199        resp = await self._request(
1200            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1201        )
1202        assert isinstance(resp, dict)
1203        return resp
1204
1205    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1208        assert isinstance(resp, dict)
1209        return resp
1210
1211    async def fetch_public_milestone_content(
1212        self, milestone_hash: int, /
1213    ) -> typedefs.JSONObject:
1214        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1215        resp = await self._request(
1216            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1217        )
1218        assert isinstance(resp, dict)
1219        return resp
1220
1221    async def fetch_current_user_memberships(
1222        self, access_token: str, /
1223    ) -> typedefs.JSONObject:
1224        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1225        resp = await self._request(
1226            RequestMethod.GET,
1227            "User/GetMembershipsForCurrentUser/",
1228            auth=access_token,
1229        )
1230        assert isinstance(resp, dict)
1231        return resp
1232
1233    async def equip_item(
1234        self,
1235        access_token: str,
1236        /,
1237        item_id: int,
1238        character_id: int,
1239        membership_type: typedefs.IntAnd[enums.MembershipType],
1240    ) -> None:
1241        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1242        payload = {
1243            "itemId": item_id,
1244            "characterId": character_id,
1245            "membershipType": int(membership_type),
1246        }
1247
1248        await self._request(
1249            RequestMethod.POST,
1250            "Destiny2/Actions/Items/EquipItem/",
1251            json=payload,
1252            auth=access_token,
1253        )
1254
1255    async def equip_items(
1256        self,
1257        access_token: str,
1258        /,
1259        item_ids: list[int],
1260        character_id: int,
1261        membership_type: typedefs.IntAnd[enums.MembershipType],
1262    ) -> None:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        payload = {
1265            "itemIds": item_ids,
1266            "characterId": character_id,
1267            "membershipType": int(membership_type),
1268        }
1269        await self._request(
1270            RequestMethod.POST,
1271            "Destiny2/Actions/Items/EquipItems/",
1272            json=payload,
1273            auth=access_token,
1274        )
1275
1276    async def ban_clan_member(
1277        self,
1278        access_token: str,
1279        /,
1280        group_id: int,
1281        membership_id: int,
1282        membership_type: typedefs.IntAnd[enums.MembershipType],
1283        *,
1284        length: int = 0,
1285        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1286    ) -> None:
1287        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1288        payload = {"comment": str(comment), "length": length}
1289        await self._request(
1290            RequestMethod.POST,
1291            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1292            json=payload,
1293            auth=access_token,
1294        )
1295
1296    async def unban_clan_member(
1297        self,
1298        access_token: str,
1299        /,
1300        group_id: int,
1301        membership_id: int,
1302        membership_type: typedefs.IntAnd[enums.MembershipType],
1303    ) -> None:
1304        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1305        await self._request(
1306            RequestMethod.POST,
1307            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1308            auth=access_token,
1309        )
1310
1311    async def kick_clan_member(
1312        self,
1313        access_token: str,
1314        /,
1315        group_id: int,
1316        membership_id: int,
1317        membership_type: typedefs.IntAnd[enums.MembershipType],
1318    ) -> typedefs.JSONObject:
1319        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1320        resp = await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1323            auth=access_token,
1324        )
1325        assert isinstance(resp, dict)
1326        return resp
1327
1328    async def edit_clan(
1329        self,
1330        access_token: str,
1331        /,
1332        group_id: int,
1333        *,
1334        name: typedefs.NoneOr[str] = None,
1335        about: typedefs.NoneOr[str] = None,
1336        motto: typedefs.NoneOr[str] = None,
1337        theme: typedefs.NoneOr[str] = None,
1338        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1339        is_public: typedefs.NoneOr[bool] = None,
1340        locale: typedefs.NoneOr[str] = None,
1341        avatar_image_index: typedefs.NoneOr[int] = None,
1342        membership_option: typedefs.NoneOr[
1343            typedefs.IntAnd[enums.MembershipOption]
1344        ] = None,
1345        allow_chat: typedefs.NoneOr[bool] = None,
1346        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1347        call_sign: typedefs.NoneOr[str] = None,
1348        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1349        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1350        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1351        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1352    ) -> None:
1353        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1354        payload = {
1355            "name": name,
1356            "about": about,
1357            "motto": motto,
1358            "theme": theme,
1359            "tags": tags,
1360            "isPublic": is_public,
1361            "avatarImageIndex": avatar_image_index,
1362            "isPublicTopicAdminOnly": is_public_topic_admin,
1363            "allowChat": allow_chat,
1364            "chatSecurity": chat_security,
1365            "callsign": call_sign,
1366            "homepage": homepage,
1367            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1368            "defaultPublicity": default_publicity,
1369            "locale": locale,
1370        }
1371        if membership_option is not None:
1372            payload["membershipOption"] = int(membership_option)
1373
1374        await self._request(
1375            RequestMethod.POST,
1376            f"GroupV2/{group_id}/Edit",
1377            json=payload,
1378            auth=access_token,
1379        )
1380
1381    async def edit_clan_options(
1382        self,
1383        access_token: str,
1384        /,
1385        group_id: int,
1386        *,
1387        invite_permissions_override: typedefs.NoneOr[bool] = None,
1388        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1389        host_guided_game_permission_override: typedefs.NoneOr[
1390            typing.Literal[0, 1, 2]
1391        ] = None,
1392        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1393        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1394    ) -> None:
1395
1396        payload = {
1397            "InvitePermissionOverride": invite_permissions_override,
1398            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1399            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1400            "UpdateBannerPermissionOverride": update_banner_permission_override,
1401            "JoinLevel": int(join_level) if join_level else None,
1402        }
1403
1404        await self._request(
1405            RequestMethod.POST,
1406            f"GroupV2/{group_id}/EditFounderOptions",
1407            json=payload,
1408            auth=access_token,
1409        )
1410
1411    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1412        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1413        resp = await self._request(
1414            RequestMethod.GET,
1415            "Social/Friends/",
1416            auth=access_token,
1417        )
1418        assert isinstance(resp, dict)
1419        return resp
1420
1421    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1422        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1423        resp = await self._request(
1424            RequestMethod.GET,
1425            "Social/Friends/Requests",
1426            auth=access_token,
1427        )
1428        assert isinstance(resp, dict)
1429        return resp
1430
1431    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1432        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1433        await self._request(
1434            RequestMethod.POST,
1435            f"Social/Friends/Requests/Accept/{member_id}",
1436            auth=access_token,
1437        )
1438
1439    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1440        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1441        await self._request(
1442            RequestMethod.POST,
1443            f"Social/Friends/Add/{member_id}",
1444            auth=access_token,
1445        )
1446
1447    async def decline_friend_request(
1448        self, access_token: str, /, member_id: int
1449    ) -> None:
1450        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1451        await self._request(
1452            RequestMethod.POST,
1453            f"Social/Friends/Requests/Decline/{member_id}",
1454            auth=access_token,
1455        )
1456
1457    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1458        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1459        await self._request(
1460            RequestMethod.POST,
1461            f"Social/Friends/Remove/{member_id}",
1462            auth=access_token,
1463        )
1464
1465    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1466        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1467        await self._request(
1468            RequestMethod.POST,
1469            f"Social/Friends/Requests/Remove/{member_id}",
1470            auth=access_token,
1471        )
1472
1473    async def approve_all_pending_group_users(
1474        self,
1475        access_token: str,
1476        /,
1477        group_id: int,
1478        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1479    ) -> None:
1480        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1481        await self._request(
1482            RequestMethod.POST,
1483            f"GroupV2/{group_id}/Members/ApproveAll",
1484            auth=access_token,
1485            json={"message": str(message)},
1486        )
1487
1488    async def deny_all_pending_group_users(
1489        self,
1490        access_token: str,
1491        /,
1492        group_id: int,
1493        *,
1494        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1495    ) -> None:
1496        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1497        await self._request(
1498            RequestMethod.POST,
1499            f"GroupV2/{group_id}/Members/DenyAll",
1500            auth=access_token,
1501            json={"message": str(message)},
1502        )
1503
1504    async def add_optional_conversation(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        *,
1510        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1511        security: typing.Literal[0, 1] = 0,
1512    ) -> None:
1513        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1514        payload = {"chatName": str(name), "chatSecurity": security}
1515        await self._request(
1516            RequestMethod.POST,
1517            f"GroupV2/{group_id}/OptionalConversations/Add",
1518            json=payload,
1519            auth=access_token,
1520        )
1521
1522    async def edit_optional_conversation(
1523        self,
1524        access_token: str,
1525        /,
1526        group_id: int,
1527        conversation_id: int,
1528        *,
1529        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1530        security: typing.Literal[0, 1] = 0,
1531        enable_chat: bool = False,
1532    ) -> None:
1533        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1534        payload = {
1535            "chatEnabled": enable_chat,
1536            "chatName": str(name),
1537            "chatSecurity": security,
1538        }
1539        await self._request(
1540            RequestMethod.POST,
1541            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1542            json=payload,
1543            auth=access_token,
1544        )
1545
1546    async def transfer_item(
1547        self,
1548        access_token: str,
1549        /,
1550        item_id: int,
1551        item_hash: int,
1552        character_id: int,
1553        member_type: typedefs.IntAnd[enums.MembershipType],
1554        *,
1555        stack_size: int = 1,
1556        vault: bool = False,
1557    ) -> None:
1558        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1559        payload = {
1560            "characterId": character_id,
1561            "membershipType": int(member_type),
1562            "itemId": item_id,
1563            "itemReferenceHash": item_hash,
1564            "stackSize": stack_size,
1565            "transferToVault": vault,
1566        }
1567        await self._request(
1568            RequestMethod.POST,
1569            "Destiny2/Actions/Items/TransferItem",
1570            json=payload,
1571            auth=access_token,
1572        )
1573
1574    async def pull_item(
1575        self,
1576        access_token: str,
1577        /,
1578        item_id: int,
1579        item_hash: int,
1580        character_id: int,
1581        member_type: typedefs.IntAnd[enums.MembershipType],
1582        *,
1583        stack_size: int = 1,
1584        vault: bool = False,
1585    ) -> None:
1586        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1587        payload = {
1588            "characterId": character_id,
1589            "membershipType": int(member_type),
1590            "itemId": item_id,
1591            "itemReferenceHash": item_hash,
1592            "stackSize": stack_size,
1593            "transferToVault": vault,
1594        }
1595        await self._request(
1596            RequestMethod.POST,
1597            "Destiny2/Actions/Items/PullFromPostmaster",
1598            json=payload,
1599            auth=access_token,
1600        )
1601
1602    async def fetch_fireteams(
1603        self,
1604        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1605        *,
1606        platform: typedefs.IntAnd[
1607            fireteams.FireteamPlatform
1608        ] = fireteams.FireteamPlatform.ANY,
1609        language: typing.Union[
1610            fireteams.FireteamLanguage, str
1611        ] = fireteams.FireteamLanguage.ALL,
1612        date_range: typedefs.IntAnd[
1613            fireteams.FireteamDate
1614        ] = fireteams.FireteamDate.ALL,
1615        page: int = 0,
1616        slots_filter: int = 0,
1617    ) -> typedefs.JSONObject:
1618        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1619        resp = await self._request(
1620            RequestMethod.GET,
1621            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1622        )
1623        assert isinstance(resp, dict)
1624        return resp
1625
1626    async def fetch_avaliable_clan_fireteams(
1627        self,
1628        access_token: str,
1629        group_id: int,
1630        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1631        *,
1632        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1633        language: typing.Union[fireteams.FireteamLanguage, str],
1634        date_range: typedefs.IntAnd[
1635            fireteams.FireteamDate
1636        ] = fireteams.FireteamDate.ALL,
1637        page: int = 0,
1638        public_only: bool = False,
1639        slots_filter: int = 0,
1640    ) -> typedefs.JSONObject:
1641        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1642        resp = await self._request(
1643            RequestMethod.GET,
1644            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1645            json={"langFilter": str(language)},
1646            auth=access_token,
1647        )
1648        assert isinstance(resp, dict)
1649        return resp
1650
1651    async def fetch_clan_fireteam(
1652        self, access_token: str, fireteam_id: int, group_id: int
1653    ) -> typedefs.JSONObject:
1654        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1655        resp = await self._request(
1656            RequestMethod.GET,
1657            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1658            auth=access_token,
1659        )
1660        assert isinstance(resp, dict)
1661        return resp
1662
1663    async def fetch_my_clan_fireteams(
1664        self,
1665        access_token: str,
1666        group_id: int,
1667        *,
1668        include_closed: bool = True,
1669        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1670        language: typing.Union[fireteams.FireteamLanguage, str],
1671        filtered: bool = True,
1672        page: int = 0,
1673    ) -> typedefs.JSONObject:
1674        payload = {"groupFilter": filtered, "langFilter": str(language)}
1675        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1676        resp = await self._request(
1677            RequestMethod.GET,
1678            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1679            json=payload,
1680            auth=access_token,
1681        )
1682        assert isinstance(resp, dict)
1683        return resp
1684
1685    async def fetch_private_clan_fireteams(
1686        self, access_token: str, group_id: int, /
1687    ) -> int:
1688        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1689        resp = await self._request(
1690            RequestMethod.GET,
1691            f"Fireteam/Clan/{group_id}/ActiveCount",
1692            auth=access_token,
1693        )
1694        assert isinstance(resp, int)
1695        return resp
1696
1697    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1698        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1699        resp = await self._request(
1700            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1701        )
1702        assert isinstance(resp, dict)
1703        return resp
1704
1705    async def search_entities(
1706        self, name: str, entity_type: str, *, page: int = 0
1707    ) -> typedefs.JSONObject:
1708        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1709        resp = await self._request(
1710            RequestMethod.GET,
1711            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1712            json={"page": page},
1713        )
1714        assert isinstance(resp, dict)
1715        return resp
1716
1717    async def fetch_unique_weapon_history(
1718        self,
1719        membership_id: int,
1720        character_id: int,
1721        membership_type: typedefs.IntAnd[enums.MembershipType],
1722    ) -> typedefs.JSONObject:
1723        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1724        resp = await self._request(
1725            RequestMethod.GET,
1726            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1727        )
1728        assert isinstance(resp, dict)
1729        return resp
1730
1731    async def fetch_item(
1732        self,
1733        member_id: int,
1734        item_id: int,
1735        membership_type: typedefs.IntAnd[enums.MembershipType],
1736        components: list[enums.ComponentType],
1737    ) -> typedefs.JSONObject:
1738        collector = _collect_components(components)
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1743        )
1744        assert isinstance(resp, dict)
1745        return resp
1746
1747    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1748        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1749        resp = await self._request(
1750            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1751        )
1752        assert isinstance(resp, dict)
1753        return resp
1754
1755    async def fetch_available_locales(self) -> typedefs.JSONObject:
1756        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1757        resp = await self._request(
1758            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1759        )
1760        assert isinstance(resp, dict)
1761        return resp
1762
1763    async def fetch_common_settings(self) -> typedefs.JSONObject:
1764        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1765        resp = await self._request(RequestMethod.GET, "Settings")
1766        assert isinstance(resp, dict)
1767        return resp
1768
1769    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1772        assert isinstance(resp, dict)
1773        return resp
1774
1775    async def fetch_global_alerts(
1776        self, *, include_streaming: bool = False
1777    ) -> typedefs.JSONArray:
1778        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1779        resp = await self._request(
1780            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1781        )
1782        assert isinstance(resp, list)
1783        return resp
1784
1785    async def awainitialize_request(
1786        self,
1787        access_token: str,
1788        type: typing.Literal[0, 1],
1789        membership_type: typedefs.IntAnd[enums.MembershipType],
1790        /,
1791        *,
1792        affected_item_id: typing.Optional[int] = None,
1793        character_id: typing.Optional[int] = None,
1794    ) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796
1797        body = {"type": type, "membershipType": int(membership_type)}
1798
1799        if affected_item_id is not None:
1800            body["affectedItemId"] = affected_item_id
1801
1802        if character_id is not None:
1803            body["characterId"] = character_id
1804
1805        resp = await self._request(
1806            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1807        )
1808        assert isinstance(resp, dict)
1809        return resp
1810
1811    async def awaget_action_token(
1812        self, access_token: str, correlation_id: str, /
1813    ) -> typedefs.JSONObject:
1814        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1815        resp = await self._request(
1816            RequestMethod.POST,
1817            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1818            auth=access_token,
1819        )
1820        assert isinstance(resp, dict)
1821        return resp
1822
1823    async def awa_provide_authorization_result(
1824        self,
1825        access_token: str,
1826        selection: int,
1827        correlation_id: str,
1828        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1829    ) -> int:
1830        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1831
1832        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1833
1834        resp = await self._request(
1835            RequestMethod.POST,
1836            "Destiny2/Awa/AwaProvideAuthorizationResult",
1837            json=body,
1838            auth=access_token,
1839        )
1840        assert isinstance(resp, int)
1841        return resp
1842
1843    async def fetch_vendors(
1844        self,
1845        access_token: str,
1846        character_id: int,
1847        membership_id: int,
1848        membership_type: typedefs.IntAnd[enums.MembershipType],
1849        /,
1850        components: list[enums.ComponentType],
1851        filter: typing.Optional[int] = None,
1852    ) -> typedefs.JSONObject:
1853        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1854        components_ = _collect_components(components)
1855        route = (
1856            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1857            f"/Character/{character_id}/Vendors/?components={components_}"
1858        )
1859
1860        if filter is not None:
1861            route = route + f"&filter={filter}"
1862
1863        resp = await self._request(
1864            RequestMethod.GET,
1865            route,
1866            auth=access_token,
1867        )
1868        assert isinstance(resp, dict)
1869        return resp
1870
1871    async def fetch_vendor(
1872        self,
1873        access_token: str,
1874        character_id: int,
1875        membership_id: int,
1876        membership_type: typedefs.IntAnd[enums.MembershipType],
1877        vendor_hash: int,
1878        /,
1879        components: list[enums.ComponentType],
1880    ) -> typedefs.JSONObject:
1881        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1882        components_ = _collect_components(components)
1883        resp = await self._request(
1884            RequestMethod.GET,
1885            (
1886                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1887                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1888            ),
1889            auth=access_token,
1890        )
1891        assert isinstance(resp, dict)
1892        return resp
1893
1894    async def fetch_application_api_usage(
1895        self,
1896        access_token: str,
1897        application_id: int,
1898        /,
1899        *,
1900        start: typing.Optional[datetime.datetime] = None,
1901        end: typing.Optional[datetime.datetime] = None,
1902    ) -> typedefs.JSONObject:
1903
1904        end_date, start_date = time.parse_date_range(end, start)
1905        resp = await self._request(
1906            RequestMethod.GET,
1907            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1908            auth=access_token,
1909        )
1910        assert isinstance(resp, dict)
1911        return resp
1912
1913    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1914        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1915        assert isinstance(resp, list)
1916        return resp
1917
1918    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1919        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1920        assert isinstance(resp, dict)
1921        return resp
1922
1923    async def fetch_content_by_id(
1924        self, id: int, locale: str, /, *, head: bool = False
1925    ) -> typedefs.JSONObject:
1926        resp = await self._request(
1927            RequestMethod.GET,
1928            f"Content/GetContentById/{id}/{locale}/",
1929            json={"head": head},
1930        )
1931        assert isinstance(resp, dict)
1932        return resp
1933
1934    async def fetch_content_by_tag_and_type(
1935        self, locale: str, tag: str, type: str, *, head: bool = False
1936    ) -> typedefs.JSONObject:
1937        resp = await self._request(
1938            RequestMethod.GET,
1939            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1940            json={"head": head},
1941        )
1942        assert isinstance(resp, dict)
1943        return resp
1944
1945    async def search_content_with_text(
1946        self,
1947        locale: str,
1948        /,
1949        content_type: str,
1950        search_text: str,
1951        tag: str,
1952        *,
1953        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1954        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1955    ) -> typedefs.JSONObject:
1956
1957        body: typedefs.JSONObject = {}
1958
1959        body["ctype"] = content_type
1960        body["searchtext"] = search_text
1961        body["tag"] = tag
1962
1963        if page is not undefined.UNDEFINED:
1964            body["currentpage"] = page
1965        else:
1966            body["currentpage"] = 1
1967
1968        if source is not undefined.UNDEFINED:
1969            body["source"] = source
1970        else:
1971            source = ""
1972        resp = await self._request(
1973            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1974        )
1975        assert isinstance(resp, dict)
1976        return resp
1977
1978    async def search_content_by_tag_and_type(
1979        self,
1980        locale: str,
1981        tag: str,
1982        type: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1985    ) -> typedefs.JSONObject:
1986        body: typedefs.JSONObject = {}
1987        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1988        resp = await self._request(
1989            RequestMethod.GET,
1990            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1991            json=body,
1992        )
1993        assert isinstance(resp, dict)
1994        return resp
1995
1996    async def search_help_articles(
1997        self, text: str, size: str, /
1998    ) -> typedefs.JSONObject:
1999        resp = await self._request(
2000            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2001        )
2002        assert isinstance(resp, dict)
2003        return resp
2004
2005    async def fetch_topics_page(
2006        self,
2007        category_filter: int,
2008        group: int,
2009        date_filter: int,
2010        sort: typing.Union[str, bytes],
2011        *,
2012        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2013        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2014        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2015    ) -> typedefs.JSONObject:
2016
2017        body: typedefs.JSONObject = {}
2018        if locales is not undefined.UNDEFINED:
2019            body["locales"] = ",".join(str(locales))
2020        else:
2021            body["locales"] = ",".join([])
2022
2023        if tag_filter is not undefined.UNDEFINED:
2024            body["tagstring"] = tag_filter
2025        else:
2026            body["tagstring"] = ""
2027
2028        page = 0 if page is not undefined.UNDEFINED else page
2029
2030        resp = await self._request(
2031            RequestMethod.GET,
2032            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2033            json=body,
2034        )
2035        assert isinstance(resp, dict)
2036        return resp
2037
2038    async def fetch_core_topics_page(
2039        self,
2040        category_filter: int,
2041        date_filter: int,
2042        sort: typing.Union[str, bytes],
2043        *,
2044        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2045        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2046    ) -> typedefs.JSONObject:
2047        body: typedefs.JSONObject = {}
2048
2049        if locales is not undefined.UNDEFINED:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        resp = await self._request(
2055            RequestMethod.GET,
2056            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2057            f"/{sort!s}/{date_filter}/{category_filter}/",
2058            json=body,
2059        )
2060        assert isinstance(resp, dict)
2061        return resp
2062
2063    async def fetch_posts_threaded_page(
2064        self,
2065        parent_post: bool,
2066        page: int,
2067        page_size: int,
2068        parent_post_id: int,
2069        reply_size: int,
2070        root_thread_mode: bool,
2071        sort_mode: int,
2072        show_banned: typing.Optional[str] = None,
2073    ) -> typedefs.JSONObject:
2074        resp = await self._request(
2075            RequestMethod.GET,
2076            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2077            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2078            json={"showbanned": show_banned},
2079        )
2080        assert isinstance(resp, dict)
2081        return resp
2082
2083    async def fetch_posts_threaded_page_from_child(
2084        self,
2085        child_id: bool,
2086        page: int,
2087        page_size: int,
2088        reply_size: int,
2089        root_thread_mode: bool,
2090        sort_mode: int,
2091        show_banned: typing.Optional[str] = None,
2092    ) -> typedefs.JSONObject:
2093        resp = await self._request(
2094            RequestMethod.GET,
2095            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2096            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2097            json={"showbanned": show_banned},
2098        )
2099        assert isinstance(resp, dict)
2100        return resp
2101
2102    async def fetch_post_and_parent(
2103        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostAndParent/{child_id}/",
2108            json={"showbanned": show_banned},
2109        )
2110        assert isinstance(resp, dict)
2111        return resp
2112
2113    async def fetch_posts_and_parent_awaiting(
2114        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2115    ) -> typedefs.JSONObject:
2116        resp = await self._request(
2117            RequestMethod.GET,
2118            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2119            json={"showbanned": show_banned},
2120        )
2121        assert isinstance(resp, dict)
2122        return resp
2123
2124    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2125        resp = await self._request(
2126            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2127        )
2128        assert isinstance(resp, int)
2129        return resp
2130
2131    async def fetch_forum_tag_suggestions(
2132        self, partial_tag: str, /
2133    ) -> typedefs.JSONObject:
2134        resp = await self._request(
2135            RequestMethod.GET,
2136            "Forum/GetForumTagSuggestions/",
2137            json={"partialtag": partial_tag},
2138        )
2139        assert isinstance(resp, dict)
2140        return resp
2141
2142    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2143        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2144        assert isinstance(resp, dict)
2145        return resp
2146
2147    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2148        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2149        assert isinstance(resp, list)
2150        return resp
2151
2152    async def fetch_recommended_groups(
2153        self,
2154        accecss_token: str,
2155        /,
2156        *,
2157        date_range: int = 0,
2158        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2159    ) -> typedefs.JSONArray:
2160        resp = await self._request(
2161            RequestMethod.POST,
2162            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2163            auth=accecss_token,
2164        )
2165        assert isinstance(resp, list)
2166        return resp
2167
2168    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2169        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2170        assert isinstance(resp, dict)
2171        return resp
2172
2173    async def fetch_user_clan_invite_setting(
2174        self,
2175        access_token: str,
2176        /,
2177        membership_type: typedefs.IntAnd[enums.MembershipType],
2178    ) -> bool:
2179        resp = await self._request(
2180            RequestMethod.GET,
2181            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2182            auth=access_token,
2183        )
2184        assert isinstance(resp, bool)
2185        return resp
2186
2187    async def fetch_banned_group_members(
2188        self, access_token: str, group_id: int, /, *, page: int = 1
2189    ) -> typedefs.JSONObject:
2190        resp = await self._request(
2191            RequestMethod.GET,
2192            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2193            auth=access_token,
2194        )
2195        assert isinstance(resp, dict)
2196        return resp
2197
2198    async def fetch_pending_group_memberships(
2199        self, access_token: str, group_id: int, /, *, current_page: int = 1
2200    ) -> typedefs.JSONObject:
2201        resp = await self._request(
2202            RequestMethod.GET,
2203            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2204            auth=access_token,
2205        )
2206        assert isinstance(resp, dict)
2207        return resp
2208
2209    async def fetch_invited_group_memberships(
2210        self, access_token: str, group_id: int, /, *, current_page: int = 1
2211    ) -> typedefs.JSONObject:
2212        resp = await self._request(
2213            RequestMethod.GET,
2214            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2215            auth=access_token,
2216        )
2217        assert isinstance(resp, dict)
2218        return resp
2219
2220    async def invite_member_to_group(
2221        self,
2222        access_token: str,
2223        /,
2224        group_id: int,
2225        membership_id: int,
2226        membership_type: typedefs.IntAnd[enums.MembershipType],
2227        *,
2228        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2229    ) -> typedefs.JSONObject:
2230        resp = await self._request(
2231            RequestMethod.POST,
2232            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2233            auth=access_token,
2234            json={"message": str(message)},
2235        )
2236        assert isinstance(resp, dict)
2237        return resp
2238
2239    async def cancel_group_member_invite(
2240        self,
2241        access_token: str,
2242        /,
2243        group_id: int,
2244        membership_id: int,
2245        membership_type: typedefs.IntAnd[enums.MembershipType],
2246    ) -> typedefs.JSONObject:
2247        resp = await self._request(
2248            RequestMethod.POST,
2249            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2250            auth=access_token,
2251        )
2252        assert isinstance(resp, dict)
2253        return resp
2254
2255    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2256        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2257        assert isinstance(resp, dict)
2258        return resp
2259
2260    async def fetch_historical_stats(
2261        self,
2262        character_id: int,
2263        membership_id: int,
2264        membership_type: typedefs.IntAnd[enums.MembershipType],
2265        day_start: datetime.datetime,
2266        day_end: datetime.datetime,
2267        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2268        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2269        *,
2270        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2271    ) -> typedefs.JSONObject:
2272
2273        end, start = time.parse_date_range(day_end, day_start)
2274        resp = await self._request(
2275            RequestMethod.GET,
2276            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2277            json={
2278                "dayend": end,
2279                "daystart": start,
2280                "groups": [str(int(group)) for group in groups],
2281                "modes": [str(int(mode)) for mode in modes],
2282                "periodType": int(period_type),
2283            },
2284        )
2285        assert isinstance(resp, dict)
2286        return resp
2287
2288    async def fetch_historical_stats_for_account(
2289        self,
2290        membership_id: int,
2291        membership_type: typedefs.IntAnd[enums.MembershipType],
2292        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2293    ) -> typedefs.JSONObject:
2294        resp = await self._request(
2295            RequestMethod.GET,
2296            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2297            json={"groups": [str(int(group)) for group in groups]},
2298        )
2299        assert isinstance(resp, dict)
2300        return resp
2301
2302    async def fetch_aggregated_activity_stats(
2303        self,
2304        character_id: int,
2305        membership_id: int,
2306        membership_type: typedefs.IntAnd[enums.MembershipType],
2307        /,
2308    ) -> typedefs.JSONObject:
2309        resp = await self._request(
2310            RequestMethod.GET,
2311            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2312            f"Character/{character_id}/Stats/AggregateActivityStats/",
2313        )
2314        assert isinstance(resp, dict)
2315        return resp

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
409    def __init__(
410        self,
411        token: str,
412        /,
413        client_secret: typing.Optional[str] = None,
414        client_id: typing.Optional[int] = None,
415        *,
416        max_retries: int = 4,
417        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
418    ) -> None:
419        self._session: typing.Optional[_Session] = None
420        self._lock: typing.Optional[asyncio.Lock] = None
421        self._client_secret = client_secret
422        self._client_id = client_id
423        self._token: str = token
424        self._max_retries = max_retries
425        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
426
427        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
441    @typing.final
442    async def close(self) -> None:
443        session = self._get_session()
444        await session.close()
445        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
447    @typing.final
448    def open(self) -> None:
449        """Open a new client session. This is called internally with contextmanager usage."""
450        if self.is_alive:
451            raise RuntimeError("Cannot open a new session while it's already open.")
452
453        self._session = _Session.create(owner=False, raise_status=False)

Open a new client session. This is called internally with contextmanager usage.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
455    @typing.final
456    def enable_debugging(
457        self,
458        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
459        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
460        /,
461    ) -> None:
462        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[aiobungie.RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
464    @typing.final
465    async def static_request(
466        self,
467        method: typing.Union[RequestMethod, str],
468        path: str,
469        *,
470        auth: typing.Optional[str] = None,
471        json: typing.Optional[dict[str, typing.Any]] = None,
472    ) -> ResponseSig:
473        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (aiobungie.RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url( self, client_id: Optional[int] = None) -> Optional[aiobungie.builders.OAuthURL]:
475    @typing.final
476    def build_oauth2_url(
477        self, client_id: typing.Optional[int] = None
478    ) -> typing.Optional[builders.OAuthURL]:
479        client_id = client_id or self._client_id
480        if client_id is None:
481            return None
482
483        return builders.OAuthURL(client_id=client_id)

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

You can't get the complete string URL by using .compile() method.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
699    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
700        if not isinstance(self._client_secret, (str, int)):
701            raise TypeError(
702                "Expected (str, int) for client secret "
703                f"but got {type(self._client_secret).__name__}"  # type: ignore
704            )
705
706        headers = {
707            "client_secret": self._client_secret,
708        }
709
710        data = (
711            f"grant_type=authorization_code&code={code}"
712            f"&client_id={self._client_id}&client_secret={self._client_secret}"
713        )
714
715        response = await self._request(
716            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
717        )
718        assert isinstance(response, dict)
719        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
721    async def refresh_access_token(
722        self, refresh_token: str, /
723    ) -> builders.OAuth2Response:
724        if not isinstance(self._client_secret, (int, str)):
725            raise TypeError(
726                f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}"  # type: ignore
727            )
728
729        data = {
730            "grant_type": "refresh_token",
731            "refresh_token": refresh_token,
732            "client_id": self._client_id,
733            "client_secret": self._client_secret,
734            "Content-Type": "application/x-www-form-urlencoded",
735        }
736
737        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
738        assert isinstance(response, dict)
739        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
741    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
742        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
743        resp = await self._request(
744            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
745        )
746        assert isinstance(resp, dict)
747        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
749    async def fetch_user_themes(self) -> typedefs.JSONArray:
750        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
751        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
752        assert isinstance(resp, list)
753        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
755    async def fetch_membership_from_id(
756        self,
757        id: int,
758        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
759        /,
760    ) -> typedefs.JSONObject:
761        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
762        resp = await self._request(
763            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
764        )
765        assert isinstance(resp, dict)
766        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
768    async def fetch_player(
769        self,
770        name: str,
771        code: int,
772        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
773        /,
774    ) -> typedefs.JSONArray:
775        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
776        resp = await self._request(
777            RequestMethod.POST,
778            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
779            json={"displayName": name, "displayNameCode": code},
780        )
781        assert isinstance(resp, list)
782        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
784    async def search_users(self, name: str, /) -> typedefs.JSONObject:
785        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
786        resp = await self._request(
787            RequestMethod.POST,
788            "User/Search/GlobalName/0",
789            json={"displayNamePrefix": name},
790        )
791        assert isinstance(resp, dict)
792        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
794    async def fetch_clan_from_id(
795        self, id: int, /, access_token: typing.Optional[str] = None
796    ) -> typedefs.JSONObject:
797        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
798        resp = await self._request(
799            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
800        )
801        assert isinstance(resp, dict)
802        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
804    async def fetch_clan(
805        self,
806        name: str,
807        /,
808        access_token: typing.Optional[str] = None,
809        *,
810        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
811    ) -> typedefs.JSONObject:
812        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
813        resp = await self._request(
814            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
815        )
816        assert isinstance(resp, dict)
817        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
819    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
820        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
821        resp = await self._request(
822            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
823        )
824        assert isinstance(resp, dict)
825        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
827    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
828        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
829        resp = await self._request(
830            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
831        )
832        assert isinstance(resp, list)
833        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
835    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
836        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
837        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
838        assert isinstance(resp, dict)
839        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
841    async def fetch_character(
842        self,
843        member_id: int,
844        membership_type: typedefs.IntAnd[enums.MembershipType],
845        character_id: int,
846        components: list[enums.ComponentType],
847        auth: typing.Optional[str] = None,
848    ) -> typedefs.JSONObject:
849        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
850        collector = _collect_components(components)
851        response = await self._request(
852            RequestMethod.GET,
853            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
854            f"Character/{character_id}/?components={collector}",
855            auth=auth,
856        )
857        assert isinstance(response, dict)
858        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
860    async def fetch_activities(
861        self,
862        member_id: int,
863        character_id: int,
864        mode: typedefs.IntAnd[enums.GameMode],
865        membership_type: typedefs.IntAnd[
866            enums.MembershipType
867        ] = enums.MembershipType.ALL,
868        *,
869        page: int = 0,
870        limit: int = 1,
871    ) -> typedefs.JSONObject:
872        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
873        resp = await self._request(
874            RequestMethod.GET,
875            f"Destiny2/{int(membership_type)}/Account/"
876            f"{member_id}/Character/{character_id}/Stats/Activities"
877            f"/?mode={int(mode)}&count={limit}&page={page}",
878        )
879        assert isinstance(resp, dict)
880        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
882    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
883        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
884        resp = await self._request(
885            RequestMethod.GET,
886            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
887        )
888        assert isinstance(resp, dict)
889        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
891    async def fetch_profile(
892        self,
893        membership_id: int,
894        type: typedefs.IntAnd[enums.MembershipType],
895        components: list[enums.ComponentType],
896        auth: typing.Optional[str] = None,
897    ) -> typedefs.JSONObject:
898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
899        collector = _collect_components(components)
900        response = await self._request(
901            RequestMethod.GET,
902            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
903            auth=auth,
904        )
905        assert isinstance(response, dict)
906        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
908    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
910        response = await self._request(
911            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
912        )
913        assert isinstance(response, dict)
914        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
916    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
917        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
918        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
919        assert isinstance(resp, dict)
920        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
922    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
923        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
924        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
925        assert isinstance(resp, dict)
926        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
928    async def fetch_groups_for_member(
929        self,
930        member_id: int,
931        member_type: typedefs.IntAnd[enums.MembershipType],
932        /,
933        *,
934        filter: int = 0,
935        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
936    ) -> typedefs.JSONObject:
937        resp = await self._request(
938            RequestMethod.GET,
939            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
940        )
941        assert isinstance(resp, dict)
942        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
944    async def fetch_potential_groups_for_member(
945        self,
946        member_id: int,
947        member_type: typedefs.IntAnd[enums.MembershipType],
948        /,
949        *,
950        filter: int = 0,
951        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
952    ) -> typedefs.JSONObject:
953        resp = await self._request(
954            RequestMethod.GET,
955            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
956        )
957        assert isinstance(resp, dict)
958        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
960    async def fetch_clan_members(
961        self,
962        clan_id: int,
963        /,
964        *,
965        name: typing.Optional[str] = None,
966        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
967    ) -> typedefs.JSONObject:
968        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
969        resp = await self._request(
970            RequestMethod.GET,
971            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
972        )
973        assert isinstance(resp, dict)
974        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
976    async def fetch_hardlinked_credentials(
977        self,
978        credential: int,
979        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
980        /,
981    ) -> typedefs.JSONObject:
982        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
983        resp = await self._request(
984            RequestMethod.GET,
985            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
986        )
987        assert isinstance(resp, dict)
988        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
990    async def fetch_user_credentials(
991        self, access_token: str, membership_id: int, /
992    ) -> typedefs.JSONArray:
993        resp = await self._request(
994            RequestMethod.GET,
995            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
996            auth=access_token,
997        )
998        assert isinstance(resp, list)
999        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1001    async def insert_socket_plug(
1002        self,
1003        action_token: str,
1004        /,
1005        instance_id: int,
1006        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1007        character_id: int,
1008        membership_type: typedefs.IntAnd[enums.MembershipType],
1009    ) -> typedefs.JSONObject:
1010
1011        if isinstance(plug, builders.PlugSocketBuilder):
1012            plug = plug.collect()
1013
1014        body = {
1015            "actionToken": action_token,
1016            "itemInstanceId": instance_id,
1017            "plug": plug,
1018            "characterId": character_id,
1019            "membershipType": int(membership_type),
1020        }
1021        resp = await self._request(
1022            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1023        )
1024        assert isinstance(resp, dict)
1025        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1027    async def insert_socket_plug_free(
1028        self,
1029        access_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "itemInstanceId": instance_id,
1042            "plug": plug,
1043            "characterId": character_id,
1044            "membershipType": int(membership_type),
1045        }
1046        resp = await self._request(
1047            RequestMethod.POST,
1048            "Destiny2/Actions/Items/InsertSocketPlugFree",
1049            json=body,
1050            auth=access_token,
1051        )
1052        assert isinstance(resp, dict)
1053        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1055    async def set_item_lock_state(
1056        self,
1057        access_token: str,
1058        state: bool,
1059        /,
1060        item_id: int,
1061        character_id: int,
1062        membership_type: typedefs.IntAnd[enums.MembershipType],
1063    ) -> int:
1064        body = {
1065            "state": state,
1066            "itemId": item_id,
1067            "characterId": character_id,
1068            "membership_type": int(membership_type),
1069        }
1070        response = await self._request(
1071            RequestMethod.POST,
1072            "Destiny2/Actions/Items/SetLockState",
1073            json=body,
1074            auth=access_token,
1075        )
1076        assert isinstance(response, int)
1077        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1079    async def set_quest_track_state(
1080        self,
1081        access_token: str,
1082        state: bool,
1083        /,
1084        item_id: int,
1085        character_id: int,
1086        membership_type: typedefs.IntAnd[enums.MembershipType],
1087    ) -> int:
1088        body = {
1089            "state": state,
1090            "itemId": item_id,
1091            "characterId": character_id,
1092            "membership_type": int(membership_type),
1093        }
1094        response = await self._request(
1095            RequestMethod.POST,
1096            "Destiny2/Actions/Items/SetTrackedState",
1097            json=body,
1098            auth=access_token,
1099        )
1100        assert isinstance(response, int)
1101        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1103    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1104        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1105        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1106        assert isinstance(path, dict)
1107        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1109    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1110        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1111        _ensure_manifest_language(language)
1112
1113        content = await self.fetch_manifest_path()
1114        resp = await self._request(
1115            RequestMethod.GET,
1116            content["mobileWorldContentPaths"][language],
1117            unwrapping="read",
1118            base=True,
1119        )
1120        assert isinstance(resp, bytes)
1121        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest', path: Union[pathlib.Path, str] = '.', *, force: bool = False) -> None:
1123    async def download_manifest(
1124        self,
1125        language: str = "en",
1126        name: str = "manifest",
1127        path: typing.Union[pathlib.Path, str] = ".",
1128        *,
1129        force: bool = False,
1130    ) -> None:
1131        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1132        complete_path = _get_path(name, path, sql=True)
1133
1134        if complete_path.exists() and force:
1135            if force:
1136                _LOG.info(
1137                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1138                )
1139                complete_path.unlink(missing_ok=True)
1140
1141                return await self.download_manifest(language, name, path, force=force)
1142
1143            else:
1144                raise FileExistsError(
1145                    "Manifest file already exists, "
1146                    "To force download, set the `force` parameter to `True`."
1147                )
1148
1149        _LOG.info(f"Downloading manifest. Location: {complete_path!s}")
1150        data_bytes = await self.read_manifest_bytes(language)
1151        await asyncio.get_running_loop().run_in_executor(
1152            None, _write_sqlite_bytes, data_bytes, path, name
1153        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • path (str | pathlib.Path): The path to save the manifest sqlite database. Example "D:/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: Union[str, pathlib.Path] = '.', language: str = 'en') -> None:
1155    async def download_json_manifest(
1156        self,
1157        file_name: str = "manifest",
1158        path: typing.Union[str, pathlib.Path] = ".",
1159        language: str = "en",
1160    ) -> None:
1161        _ensure_manifest_language(language)
1162
1163        _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...")
1164
1165        content = await self.fetch_manifest_path()
1166        json_bytes = await self._request(
1167            RequestMethod.GET,
1168            content["jsonWorldContentPaths"][language],
1169            unwrapping="read",
1170            base=True,
1171        )
1172
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_json_bytes, json_bytes, file_name, path
1175        )
1176        _LOG.info("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
async def fetch_manifest_version(self) -> str:
1178    async def fetch_manifest_version(self) -> str:
1179        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1181    async def fetch_linked_profiles(
1182        self,
1183        member_id: int,
1184        member_type: typedefs.IntAnd[enums.MembershipType],
1185        /,
1186        *,
1187        all: bool = False,
1188    ) -> typedefs.JSONObject:
1189        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1190        resp = await self._request(
1191            RequestMethod.GET,
1192            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1193        )
1194        assert isinstance(resp, dict)
1195        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1197    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1198        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1199        resp = await self._request(
1200            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1201        )
1202        assert isinstance(resp, dict)
1203        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1205    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1208        assert isinstance(resp, dict)
1209        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1211    async def fetch_public_milestone_content(
1212        self, milestone_hash: int, /
1213    ) -> typedefs.JSONObject:
1214        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1215        resp = await self._request(
1216            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1217        )
1218        assert isinstance(resp, dict)
1219        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1221    async def fetch_current_user_memberships(
1222        self, access_token: str, /
1223    ) -> typedefs.JSONObject:
1224        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1225        resp = await self._request(
1226            RequestMethod.GET,
1227            "User/GetMembershipsForCurrentUser/",
1228            auth=access_token,
1229        )
1230        assert isinstance(resp, dict)
1231        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1233    async def equip_item(
1234        self,
1235        access_token: str,
1236        /,
1237        item_id: int,
1238        character_id: int,
1239        membership_type: typedefs.IntAnd[enums.MembershipType],
1240    ) -> None:
1241        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1242        payload = {
1243            "itemId": item_id,
1244            "characterId": character_id,
1245            "membershipType": int(membership_type),
1246        }
1247
1248        await self._request(
1249            RequestMethod.POST,
1250            "Destiny2/Actions/Items/EquipItem/",
1251            json=payload,
1252            auth=access_token,
1253        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1255    async def equip_items(
1256        self,
1257        access_token: str,
1258        /,
1259        item_ids: list[int],
1260        character_id: int,
1261        membership_type: typedefs.IntAnd[enums.MembershipType],
1262    ) -> None:
1263        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1264        payload = {
1265            "itemIds": item_ids,
1266            "characterId": character_id,
1267            "membershipType": int(membership_type),
1268        }
1269        await self._request(
1270            RequestMethod.POST,
1271            "Destiny2/Actions/Items/EquipItems/",
1272            json=payload,
1273            auth=access_token,
1274        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, length: int = 0, comment: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1276    async def ban_clan_member(
1277        self,
1278        access_token: str,
1279        /,
1280        group_id: int,
1281        membership_id: int,
1282        membership_type: typedefs.IntAnd[enums.MembershipType],
1283        *,
1284        length: int = 0,
1285        comment: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1286    ) -> None:
1287        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1288        payload = {"comment": str(comment), "length": length}
1289        await self._request(
1290            RequestMethod.POST,
1291            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1292            json=payload,
1293            auth=access_token,
1294        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1296    async def unban_clan_member(
1297        self,
1298        access_token: str,
1299        /,
1300        group_id: int,
1301        membership_id: int,
1302        membership_type: typedefs.IntAnd[enums.MembershipType],
1303    ) -> None:
1304        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1305        await self._request(
1306            RequestMethod.POST,
1307            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1308            auth=access_token,
1309        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1311    async def kick_clan_member(
1312        self,
1313        access_token: str,
1314        /,
1315        group_id: int,
1316        membership_id: int,
1317        membership_type: typedefs.IntAnd[enums.MembershipType],
1318    ) -> typedefs.JSONObject:
1319        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1320        resp = await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1323            auth=access_token,
1324        )
1325        assert isinstance(resp, dict)
1326        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, aiobungie.MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1328    async def edit_clan(
1329        self,
1330        access_token: str,
1331        /,
1332        group_id: int,
1333        *,
1334        name: typedefs.NoneOr[str] = None,
1335        about: typedefs.NoneOr[str] = None,
1336        motto: typedefs.NoneOr[str] = None,
1337        theme: typedefs.NoneOr[str] = None,
1338        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1339        is_public: typedefs.NoneOr[bool] = None,
1340        locale: typedefs.NoneOr[str] = None,
1341        avatar_image_index: typedefs.NoneOr[int] = None,
1342        membership_option: typedefs.NoneOr[
1343            typedefs.IntAnd[enums.MembershipOption]
1344        ] = None,
1345        allow_chat: typedefs.NoneOr[bool] = None,
1346        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1347        call_sign: typedefs.NoneOr[str] = None,
1348        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1349        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1350        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1351        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1352    ) -> None:
1353        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1354        payload = {
1355            "name": name,
1356            "about": about,
1357            "motto": motto,
1358            "theme": theme,
1359            "tags": tags,
1360            "isPublic": is_public,
1361            "avatarImageIndex": avatar_image_index,
1362            "isPublicTopicAdminOnly": is_public_topic_admin,
1363            "allowChat": allow_chat,
1364            "chatSecurity": chat_security,
1365            "callsign": call_sign,
1366            "homepage": homepage,
1367            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1368            "defaultPublicity": default_publicity,
1369            "locale": locale,
1370        }
1371        if membership_option is not None:
1372            payload["membershipOption"] = int(membership_option)
1373
1374        await self._request(
1375            RequestMethod.POST,
1376            f"GroupV2/{group_id}/Edit",
1377            json=payload,
1378            auth=access_token,
1379        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, aiobungie.ClanMemberType] = None) -> None:
1381    async def edit_clan_options(
1382        self,
1383        access_token: str,
1384        /,
1385        group_id: int,
1386        *,
1387        invite_permissions_override: typedefs.NoneOr[bool] = None,
1388        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1389        host_guided_game_permission_override: typedefs.NoneOr[
1390            typing.Literal[0, 1, 2]
1391        ] = None,
1392        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1393        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1394    ) -> None:
1395
1396        payload = {
1397            "InvitePermissionOverride": invite_permissions_override,
1398            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1399            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1400            "UpdateBannerPermissionOverride": update_banner_permission_override,
1401            "JoinLevel": int(join_level) if join_level else None,
1402        }
1403
1404        await self._request(
1405            RequestMethod.POST,
1406            f"GroupV2/{group_id}/EditFounderOptions",
1407            json=payload,
1408            auth=access_token,
1409        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1411    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1412        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1413        resp = await self._request(
1414            RequestMethod.GET,
1415            "Social/Friends/",
1416            auth=access_token,
1417        )
1418        assert isinstance(resp, dict)
1419        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1421    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1422        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1423        resp = await self._request(
1424            RequestMethod.GET,
1425            "Social/Friends/Requests",
1426            auth=access_token,
1427        )
1428        assert isinstance(resp, dict)
1429        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1431    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1432        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1433        await self._request(
1434            RequestMethod.POST,
1435            f"Social/Friends/Requests/Accept/{member_id}",
1436            auth=access_token,
1437        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1439    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1440        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1441        await self._request(
1442            RequestMethod.POST,
1443            f"Social/Friends/Add/{member_id}",
1444            auth=access_token,
1445        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1447    async def decline_friend_request(
1448        self, access_token: str, /, member_id: int
1449    ) -> None:
1450        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1451        await self._request(
1452            RequestMethod.POST,
1453            f"Social/Friends/Requests/Decline/{member_id}",
1454            auth=access_token,
1455        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1457    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1458        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1459        await self._request(
1460            RequestMethod.POST,
1461            f"Social/Friends/Remove/{member_id}",
1462            auth=access_token,
1463        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1465    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1466        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1467        await self._request(
1468            RequestMethod.POST,
1469            f"Social/Friends/Requests/Remove/{member_id}",
1470            auth=access_token,
1471        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1473    async def approve_all_pending_group_users(
1474        self,
1475        access_token: str,
1476        /,
1477        group_id: int,
1478        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1479    ) -> None:
1480        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1481        await self._request(
1482            RequestMethod.POST,
1483            f"GroupV2/{group_id}/Members/ApproveAll",
1484            auth=access_token,
1485            json={"message": str(message)},
1486        )

Apporve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1488    async def deny_all_pending_group_users(
1489        self,
1490        access_token: str,
1491        /,
1492        group_id: int,
1493        *,
1494        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1495    ) -> None:
1496        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1497        await self._request(
1498            RequestMethod.POST,
1499            f"GroupV2/{group_id}/Members/DenyAll",
1500            auth=access_token,
1501            json={"message": str(message)},
1502        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1504    async def add_optional_conversation(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        *,
1510        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1511        security: typing.Literal[0, 1] = 0,
1512    ) -> None:
1513        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1514        payload = {"chatName": str(name), "chatSecurity": security}
1515        await self._request(
1516            RequestMethod.POST,
1517            f"GroupV2/{group_id}/OptionalConversations/Add",
1518            json=payload,
1519            auth=access_token,
1520        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1522    async def edit_optional_conversation(
1523        self,
1524        access_token: str,
1525        /,
1526        group_id: int,
1527        conversation_id: int,
1528        *,
1529        name: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1530        security: typing.Literal[0, 1] = 0,
1531        enable_chat: bool = False,
1532    ) -> None:
1533        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1534        payload = {
1535            "chatEnabled": enable_chat,
1536            "chatName": str(name),
1537            "chatSecurity": security,
1538        }
1539        await self._request(
1540            RequestMethod.POST,
1541            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1542            json=payload,
1543            auth=access_token,
1544        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1546    async def transfer_item(
1547        self,
1548        access_token: str,
1549        /,
1550        item_id: int,
1551        item_hash: int,
1552        character_id: int,
1553        member_type: typedefs.IntAnd[enums.MembershipType],
1554        *,
1555        stack_size: int = 1,
1556        vault: bool = False,
1557    ) -> None:
1558        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1559        payload = {
1560            "characterId": character_id,
1561            "membershipType": int(member_type),
1562            "itemId": item_id,
1563            "itemReferenceHash": item_hash,
1564            "stackSize": stack_size,
1565            "transferToVault": vault,
1566        }
1567        await self._request(
1568            RequestMethod.POST,
1569            "Destiny2/Actions/Items/TransferItem",
1570            json=payload,
1571            auth=access_token,
1572        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to trasnfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1574    async def pull_item(
1575        self,
1576        access_token: str,
1577        /,
1578        item_id: int,
1579        item_hash: int,
1580        character_id: int,
1581        member_type: typedefs.IntAnd[enums.MembershipType],
1582        *,
1583        stack_size: int = 1,
1584        vault: bool = False,
1585    ) -> None:
1586        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1587        payload = {
1588            "characterId": character_id,
1589            "membershipType": int(member_type),
1590            "itemId": item_id,
1591            "itemReferenceHash": item_hash,
1592            "stackSize": stack_size,
1593            "transferToVault": vault,
1594        }
1595        await self._request(
1596            RequestMethod.POST,
1597            "Destiny2/Actions/Items/PullFromPostmaster",
1598            json=payload,
1599            auth=access_token,
1600        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1602    async def fetch_fireteams(
1603        self,
1604        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1605        *,
1606        platform: typedefs.IntAnd[
1607            fireteams.FireteamPlatform
1608        ] = fireteams.FireteamPlatform.ANY,
1609        language: typing.Union[
1610            fireteams.FireteamLanguage, str
1611        ] = fireteams.FireteamLanguage.ALL,
1612        date_range: typedefs.IntAnd[
1613            fireteams.FireteamDate
1614        ] = fireteams.FireteamDate.ALL,
1615        page: int = 0,
1616        slots_filter: int = 0,
1617    ) -> typedefs.JSONObject:
1618        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1619        resp = await self._request(
1620            RequestMethod.GET,
1621            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1622        )
1623        assert isinstance(resp, dict)
1624        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1626    async def fetch_avaliable_clan_fireteams(
1627        self,
1628        access_token: str,
1629        group_id: int,
1630        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1631        *,
1632        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1633        language: typing.Union[fireteams.FireteamLanguage, str],
1634        date_range: typedefs.IntAnd[
1635            fireteams.FireteamDate
1636        ] = fireteams.FireteamDate.ALL,
1637        page: int = 0,
1638        public_only: bool = False,
1639        slots_filter: int = 0,
1640    ) -> typedefs.JSONObject:
1641        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1642        resp = await self._request(
1643            RequestMethod.GET,
1644            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1645            json={"langFilter": str(language)},
1646            auth=access_token,
1647        )
1648        assert isinstance(resp, dict)
1649        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1651    async def fetch_clan_fireteam(
1652        self, access_token: str, fireteam_id: int, group_id: int
1653    ) -> typedefs.JSONObject:
1654        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1655        resp = await self._request(
1656            RequestMethod.GET,
1657            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1658            auth=access_token,
1659        )
1660        assert isinstance(resp, dict)
1661        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1663    async def fetch_my_clan_fireteams(
1664        self,
1665        access_token: str,
1666        group_id: int,
1667        *,
1668        include_closed: bool = True,
1669        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1670        language: typing.Union[fireteams.FireteamLanguage, str],
1671        filtered: bool = True,
1672        page: int = 0,
1673    ) -> typedefs.JSONObject:
1674        payload = {"groupFilter": filtered, "langFilter": str(language)}
1675        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1676        resp = await self._request(
1677            RequestMethod.GET,
1678            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1679            json=payload,
1680            auth=access_token,
1681        )
1682        assert isinstance(resp, dict)
1683        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1685    async def fetch_private_clan_fireteams(
1686        self, access_token: str, group_id: int, /
1687    ) -> int:
1688        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1689        resp = await self._request(
1690            RequestMethod.GET,
1691            f"Fireteam/Clan/{group_id}/ActiveCount",
1692            auth=access_token,
1693        )
1694        assert isinstance(resp, int)
1695        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1697    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1698        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1699        resp = await self._request(
1700            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1701        )
1702        assert isinstance(resp, dict)
1703        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1705    async def search_entities(
1706        self, name: str, entity_type: str, *, page: int = 0
1707    ) -> typedefs.JSONObject:
1708        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1709        resp = await self._request(
1710            RequestMethod.GET,
1711            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1712            json={"page": page},
1713        )
1714        assert isinstance(resp, dict)
1715        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1717    async def fetch_unique_weapon_history(
1718        self,
1719        membership_id: int,
1720        character_id: int,
1721        membership_type: typedefs.IntAnd[enums.MembershipType],
1722    ) -> typedefs.JSONObject:
1723        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1724        resp = await self._request(
1725            RequestMethod.GET,
1726            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1727        )
1728        assert isinstance(resp, dict)
1729        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1731    async def fetch_item(
1732        self,
1733        member_id: int,
1734        item_id: int,
1735        membership_type: typedefs.IntAnd[enums.MembershipType],
1736        components: list[enums.ComponentType],
1737    ) -> typedefs.JSONObject:
1738        collector = _collect_components(components)
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1743        )
1744        assert isinstance(resp, dict)
1745        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1747    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1748        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1749        resp = await self._request(
1750            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1751        )
1752        assert isinstance(resp, dict)
1753        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1755    async def fetch_available_locales(self) -> typedefs.JSONObject:
1756        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1757        resp = await self._request(
1758            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1759        )
1760        assert isinstance(resp, dict)
1761        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1763    async def fetch_common_settings(self) -> typedefs.JSONObject:
1764        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1765        resp = await self._request(RequestMethod.GET, "Settings")
1766        assert isinstance(resp, dict)
1767        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1769    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1772        assert isinstance(resp, dict)
1773        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1775    async def fetch_global_alerts(
1776        self, *, include_streaming: bool = False
1777    ) -> typedefs.JSONArray:
1778        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1779        resp = await self._request(
1780            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1781        )
1782        assert isinstance(resp, list)
1783        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, aiobungie.MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1785    async def awainitialize_request(
1786        self,
1787        access_token: str,
1788        type: typing.Literal[0, 1],
1789        membership_type: typedefs.IntAnd[enums.MembershipType],
1790        /,
1791        *,
1792        affected_item_id: typing.Optional[int] = None,
1793        character_id: typing.Optional[int] = None,
1794    ) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796
1797        body = {"type": type, "membershipType": int(membership_type)}
1798
1799        if affected_item_id is not None:
1800            body["affectedItemId"] = affected_item_id
1801
1802        if character_id is not None:
1803            body["characterId"] = character_id
1804
1805        resp = await self._request(
1806            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1807        )
1808        assert isinstance(resp, dict)
1809        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1811    async def awaget_action_token(
1812        self, access_token: str, correlation_id: str, /
1813    ) -> typedefs.JSONObject:
1814        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1815        resp = await self._request(
1816            RequestMethod.POST,
1817            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1818            auth=access_token,
1819        )
1820        assert isinstance(resp, dict)
1821        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1823    async def awa_provide_authorization_result(
1824        self,
1825        access_token: str,
1826        selection: int,
1827        correlation_id: str,
1828        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1829    ) -> int:
1830        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1831
1832        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1833
1834        resp = await self._request(
1835            RequestMethod.POST,
1836            "Destiny2/Awa/AwaProvideAuthorizationResult",
1837            json=body,
1838            auth=access_token,
1839        )
1840        assert isinstance(resp, int)
1841        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /, components: list[aiobungie.ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1843    async def fetch_vendors(
1844        self,
1845        access_token: str,
1846        character_id: int,
1847        membership_id: int,
1848        membership_type: typedefs.IntAnd[enums.MembershipType],
1849        /,
1850        components: list[enums.ComponentType],
1851        filter: typing.Optional[int] = None,
1852    ) -> typedefs.JSONObject:
1853        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1854        components_ = _collect_components(components)
1855        route = (
1856            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1857            f"/Character/{character_id}/Vendors/?components={components_}"
1858        )
1859
1860        if filter is not None:
1861            route = route + f"&filter={filter}"
1862
1863        resp = await self._request(
1864            RequestMethod.GET,
1865            route,
1866            auth=access_token,
1867        )
1868        assert isinstance(resp, dict)
1869        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], vendor_hash: int, /, components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1871    async def fetch_vendor(
1872        self,
1873        access_token: str,
1874        character_id: int,
1875        membership_id: int,
1876        membership_type: typedefs.IntAnd[enums.MembershipType],
1877        vendor_hash: int,
1878        /,
1879        components: list[enums.ComponentType],
1880    ) -> typedefs.JSONObject:
1881        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1882        components_ = _collect_components(components)
1883        resp = await self._request(
1884            RequestMethod.GET,
1885            (
1886                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1887                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1888            ),
1889            auth=access_token,
1890        )
1891        assert isinstance(resp, dict)
1892        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1894    async def fetch_application_api_usage(
1895        self,
1896        access_token: str,
1897        application_id: int,
1898        /,
1899        *,
1900        start: typing.Optional[datetime.datetime] = None,
1901        end: typing.Optional[datetime.datetime] = None,
1902    ) -> typedefs.JSONObject:
1903
1904        end_date, start_date = time.parse_date_range(end, start)
1905        resp = await self._request(
1906            RequestMethod.GET,
1907            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1908            auth=access_token,
1909        )
1910        assert isinstance(resp, dict)
1911        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1913    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1914        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1915        assert isinstance(resp, list)
1916        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1918    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1919        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1920        assert isinstance(resp, dict)
1921        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1923    async def fetch_content_by_id(
1924        self, id: int, locale: str, /, *, head: bool = False
1925    ) -> typedefs.JSONObject:
1926        resp = await self._request(
1927            RequestMethod.GET,
1928            f"Content/GetContentById/{id}/{locale}/",
1929            json={"head": head},
1930        )
1931        assert isinstance(resp, dict)
1932        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1934    async def fetch_content_by_tag_and_type(
1935        self, locale: str, tag: str, type: str, *, head: bool = False
1936    ) -> typedefs.JSONObject:
1937        resp = await self._request(
1938            RequestMethod.GET,
1939            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1940            json={"head": head},
1941        )
1942        assert isinstance(resp, dict)
1943        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, source: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1945    async def search_content_with_text(
1946        self,
1947        locale: str,
1948        /,
1949        content_type: str,
1950        search_text: str,
1951        tag: str,
1952        *,
1953        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1954        source: undefined.UndefinedOr[str] = undefined.UNDEFINED,
1955    ) -> typedefs.JSONObject:
1956
1957        body: typedefs.JSONObject = {}
1958
1959        body["ctype"] = content_type
1960        body["searchtext"] = search_text
1961        body["tag"] = tag
1962
1963        if page is not undefined.UNDEFINED:
1964            body["currentpage"] = page
1965        else:
1966            body["currentpage"] = 1
1967
1968        if source is not undefined.UNDEFINED:
1969            body["source"] = source
1970        else:
1971            source = ""
1972        resp = await self._request(
1973            RequestMethod.GET, f"Content/Search/{locale}/", json=body
1974        )
1975        assert isinstance(resp, dict)
1976        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
1978    async def search_content_by_tag_and_type(
1979        self,
1980        locale: str,
1981        tag: str,
1982        type: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
1985    ) -> typedefs.JSONObject:
1986        body: typedefs.JSONObject = {}
1987        body["currentpage"] = 1 if page is undefined.UNDEFINED else page
1988        resp = await self._request(
1989            RequestMethod.GET,
1990            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1991            json=body,
1992        )
1993        assert isinstance(resp, dict)
1994        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
1996    async def search_help_articles(
1997        self, text: str, size: str, /
1998    ) -> typedefs.JSONObject:
1999        resp = await self._request(
2000            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2001        )
2002        assert isinstance(resp, dict)
2003        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2005    async def fetch_topics_page(
2006        self,
2007        category_filter: int,
2008        group: int,
2009        date_filter: int,
2010        sort: typing.Union[str, bytes],
2011        *,
2012        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2013        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2014        tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2015    ) -> typedefs.JSONObject:
2016
2017        body: typedefs.JSONObject = {}
2018        if locales is not undefined.UNDEFINED:
2019            body["locales"] = ",".join(str(locales))
2020        else:
2021            body["locales"] = ",".join([])
2022
2023        if tag_filter is not undefined.UNDEFINED:
2024            body["tagstring"] = tag_filter
2025        else:
2026            body["tagstring"] = ""
2027
2028        page = 0 if page is not undefined.UNDEFINED else page
2029
2030        resp = await self._request(
2031            RequestMethod.GET,
2032            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2033            json=body,
2034        )
2035        assert isinstance(resp, dict)
2036        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
2038    async def fetch_core_topics_page(
2039        self,
2040        category_filter: int,
2041        date_filter: int,
2042        sort: typing.Union[str, bytes],
2043        *,
2044        page: undefined.UndefinedOr[int] = undefined.UNDEFINED,
2045        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED,
2046    ) -> typedefs.JSONObject:
2047        body: typedefs.JSONObject = {}
2048
2049        if locales is not undefined.UNDEFINED:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        resp = await self._request(
2055            RequestMethod.GET,
2056            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}"
2057            f"/{sort!s}/{date_filter}/{category_filter}/",
2058            json=body,
2059        )
2060        assert isinstance(resp, dict)
2061        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2063    async def fetch_posts_threaded_page(
2064        self,
2065        parent_post: bool,
2066        page: int,
2067        page_size: int,
2068        parent_post_id: int,
2069        reply_size: int,
2070        root_thread_mode: bool,
2071        sort_mode: int,
2072        show_banned: typing.Optional[str] = None,
2073    ) -> typedefs.JSONObject:
2074        resp = await self._request(
2075            RequestMethod.GET,
2076            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2077            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2078            json={"showbanned": show_banned},
2079        )
2080        assert isinstance(resp, dict)
2081        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2083    async def fetch_posts_threaded_page_from_child(
2084        self,
2085        child_id: bool,
2086        page: int,
2087        page_size: int,
2088        reply_size: int,
2089        root_thread_mode: bool,
2090        sort_mode: int,
2091        show_banned: typing.Optional[str] = None,
2092    ) -> typedefs.JSONObject:
2093        resp = await self._request(
2094            RequestMethod.GET,
2095            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2096            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2097            json={"showbanned": show_banned},
2098        )
2099        assert isinstance(resp, dict)
2100        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2102    async def fetch_post_and_parent(
2103        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostAndParent/{child_id}/",
2108            json={"showbanned": show_banned},
2109        )
2110        assert isinstance(resp, dict)
2111        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2113    async def fetch_posts_and_parent_awaiting(
2114        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2115    ) -> typedefs.JSONObject:
2116        resp = await self._request(
2117            RequestMethod.GET,
2118            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2119            json={"showbanned": show_banned},
2120        )
2121        assert isinstance(resp, dict)
2122        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2124    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2125        resp = await self._request(
2126            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2127        )
2128        assert isinstance(resp, int)
2129        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2131    async def fetch_forum_tag_suggestions(
2132        self, partial_tag: str, /
2133    ) -> typedefs.JSONObject:
2134        resp = await self._request(
2135            RequestMethod.GET,
2136            "Forum/GetForumTagSuggestions/",
2137            json={"partialtag": partial_tag},
2138        )
2139        assert isinstance(resp, dict)
2140        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2142    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2143        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2144        assert isinstance(resp, dict)
2145        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2147    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2148        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2149        assert isinstance(resp, list)
2150        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2168    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2169        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2170        assert isinstance(resp, dict)
2171        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, aiobungie.MembershipType]) -> bool:
2173    async def fetch_user_clan_invite_setting(
2174        self,
2175        access_token: str,
2176        /,
2177        membership_type: typedefs.IntAnd[enums.MembershipType],
2178    ) -> bool:
2179        resp = await self._request(
2180            RequestMethod.GET,
2181            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2182            auth=access_token,
2183        )
2184        assert isinstance(resp, bool)
2185        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2187    async def fetch_banned_group_members(
2188        self, access_token: str, group_id: int, /, *, page: int = 1
2189    ) -> typedefs.JSONObject:
2190        resp = await self._request(
2191            RequestMethod.GET,
2192            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2193            auth=access_token,
2194        )
2195        assert isinstance(resp, dict)
2196        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2198    async def fetch_pending_group_memberships(
2199        self, access_token: str, group_id: int, /, *, current_page: int = 1
2200    ) -> typedefs.JSONObject:
2201        resp = await self._request(
2202            RequestMethod.GET,
2203            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2204            auth=access_token,
2205        )
2206        assert isinstance(resp, dict)
2207        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2209    async def fetch_invited_group_memberships(
2210        self, access_token: str, group_id: int, /, *, current_page: int = 1
2211    ) -> typedefs.JSONObject:
2212        resp = await self._request(
2213            RequestMethod.GET,
2214            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2215            auth=access_token,
2216        )
2217        assert isinstance(resp, dict)
2218        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2220    async def invite_member_to_group(
2221        self,
2222        access_token: str,
2223        /,
2224        group_id: int,
2225        membership_id: int,
2226        membership_type: typedefs.IntAnd[enums.MembershipType],
2227        *,
2228        message: undefined.UndefinedOr[str] = undefined.UNDEFINED,
2229    ) -> typedefs.JSONObject:
2230        resp = await self._request(
2231            RequestMethod.POST,
2232            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2233            auth=access_token,
2234            json={"message": str(message)},
2235        )
2236        assert isinstance(resp, dict)
2237        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
2239    async def cancel_group_member_invite(
2240        self,
2241        access_token: str,
2242        /,
2243        group_id: int,
2244        membership_id: int,
2245        membership_type: typedefs.IntAnd[enums.MembershipType],
2246    ) -> typedefs.JSONObject:
2247        resp = await self._request(
2248            RequestMethod.POST,
2249            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2250            auth=access_token,
2251        )
2252        assert isinstance(resp, dict)
2253        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2255    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2256        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2257        assert isinstance(resp, dict)
2258        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, aiobungie.GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2260    async def fetch_historical_stats(
2261        self,
2262        character_id: int,
2263        membership_id: int,
2264        membership_type: typedefs.IntAnd[enums.MembershipType],
2265        day_start: datetime.datetime,
2266        day_end: datetime.datetime,
2267        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2268        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2269        *,
2270        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2271    ) -> typedefs.JSONObject:
2272
2273        end, start = time.parse_date_range(day_end, day_start)
2274        resp = await self._request(
2275            RequestMethod.GET,
2276            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2277            json={
2278                "dayend": end,
2279                "daystart": start,
2280                "groups": [str(int(group)) for group in groups],
2281                "modes": [str(int(mode)) for mode in modes],
2282                "periodType": int(period_type),
2283            },
2284        )
2285        assert isinstance(resp, dict)
2286        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2288    async def fetch_historical_stats_for_account(
2289        self,
2290        membership_id: int,
2291        membership_type: typedefs.IntAnd[enums.MembershipType],
2292        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2293    ) -> typedefs.JSONObject:
2294        resp = await self._request(
2295            RequestMethod.GET,
2296            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2297            json={"groups": [str(int(group)) for group in groups]},
2298        )
2299        assert isinstance(resp, dict)
2300        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /) -> dict[str, typing.Any]:
2302    async def fetch_aggregated_activity_stats(
2303        self,
2304        character_id: int,
2305        membership_id: int,
2306        membership_type: typedefs.IntAnd[enums.MembershipType],
2307        /,
2308    ) -> typedefs.JSONObject:
2309        resp = await self._request(
2310            RequestMethod.GET,
2311            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2312            f"Character/{character_id}/Stats/AggregateActivityStats/",
2313        )
2314        assert isinstance(resp, dict)
2315        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
class RESTPool:
237class RESTPool:
238    """Pool of `RESTClient` instances.
239
240    This allows to create multiple instances of `RESTClient`s that can be acquired
241    which share the same config and metadata.
242
243    Example
244    -------
245    ```py
246    import aiobungie
247    import asyncio
248
249    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
250
251    # Using a context manager to acquire an instance
252    # of the pool and close the connection after finishing.
253
254    async def first() -> str:
255        async with client_pool.acquire() as client:
256            return client.build_oauth2_url()
257
258    async def second() -> None:
259        async with client_pool.acquire() as client:
260            new_tokens = await client.refresh_access_token("token")
261            client.metadata['tokens'] = new_tokens
262
263    # Client instances are independent from first and second.
264    await asyncio.gather(first(), second())
265    ```
266
267    Parameters
268    ----------
269    token : `str`
270        A valid application token from Bungie's developer portal.
271
272    Other Parameters
273    ----------------
274    max_retries : `int`
275        The max retries number to retry if the request hit a `5xx` status code.
276    client_secret : `typing.Optional[str]`
277        An optional application client secret,
278        This is only needed if you're fetching OAuth2 tokens with this client.
279    client_id : `typing.Optional[int]`
280        An optional application client id,
281        This is only needed if you're fetching OAuth2 tokens with this client.
282    enable_debugging : `bool | str`
283        Whether to enable logging responses or not.
284
285    Logging Levels
286    --------------
287    * `False`: This will disable logging.
288    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
289    Like the response status, route, taken time and so on.
290    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
291    """
292
293    __slots__ = (
294        "_token",
295        "_max_retries",
296        "_client_secret",
297        "_client_id",
298        "_metadata",
299        "_enable_debug",
300    )
301
302    # Looks like mypy doesn't like this.
303    if typing.TYPE_CHECKING:
304        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
305
306    def __init__(
307        self,
308        token: str,
309        /,
310        client_secret: typing.Optional[str] = None,
311        client_id: typing.Optional[int] = None,
312        *,
313        max_retries: int = 4,
314        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
315    ) -> None:
316        self._client_secret = client_secret
317        self._client_id = client_id
318        self._token: str = token
319        self._max_retries = max_retries
320        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
321        self._enable_debug = enable_debugging
322
323    @property
324    def client_id(self) -> typing.Optional[int]:
325        return self._client_id
326
327    @property
328    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
329        """Pool's Metadata. This is different from client instance metadata."""
330        return self._metadata
331
332    @typing.final
333    def acquire(self) -> RESTClient:
334        """Acquires a new `RESTClient` instance from this REST pool.
335
336        Returns
337        -------
338        `RESTClient`
339            An instance of a REST client.
340        """
341        instance = RESTClient(
342            self._token,
343            client_secret=self._client_secret,
344            client_id=self._client_id,
345            max_retries=self._max_retries,
346            enable_debugging=self._enable_debug,
347        )
348        return instance

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same config and metadata.

Example
import aiobungie
import asyncio

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async def first() -> str:
    async with client_pool.acquire() as client:
        return client.build_oauth2_url()

async def second() -> None:
    async with client_pool.acquire() as client:
        new_tokens = await client.refresh_access_token("token")
        client.metadata['tokens'] = new_tokens

# Client instances are independent from first and second.
await asyncio.gather(first(), second())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
306    def __init__(
307        self,
308        token: str,
309        /,
310        client_secret: typing.Optional[str] = None,
311        client_id: typing.Optional[int] = None,
312        *,
313        max_retries: int = 4,
314        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
315    ) -> None:
316        self._client_secret = client_secret
317        self._client_id = client_id
318        self._token: str = token
319        self._max_retries = max_retries
320        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
321        self._enable_debug = enable_debugging
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> aiobungie.RESTClient:
332    @typing.final
333    def acquire(self) -> RESTClient:
334        """Acquires a new `RESTClient` instance from this REST pool.
335
336        Returns
337        -------
338        `RESTClient`
339            An instance of a REST client.
340        """
341        instance = RESTClient(
342            self._token,
343            client_secret=self._client_secret,
344            client_id=self._client_id,
345            max_retries=self._max_retries,
346            enable_debugging=self._enable_debug,
347        )
348        return instance

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
493@typing.final
494class Race(int, Enum):
495    """An Enum for Destiny races."""
496
497    HUMAN = 0
498    AWOKEN = 1
499    EXO = 2
500    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
143@typing.final
144class Raid(int, Enum):
145    """An Enum for all available raids in Destiny 2."""
146
147    DSC = 910380154
148    """Deep Stone Crypt"""
149
150    LW = 2122313384
151    """Last Wish"""
152
153    VOG = 3881495763
154    """Normal Valut of Glass"""
155
156    GOS = 3458480158
157    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
200@attrs.define(auto_exc=True)
201class RateLimitedError(HTTPError):
202    """Raised when being hit with ratelimits."""
203
204    http_status: http.HTTPStatus = attrs.field(
205        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
206    )
207    """The request response http status."""
208
209    url: typedefs.StrOrURL
210    """The URL/endpoint caused this error."""
211
212    body: typing.Any
213    """The response body."""
214
215    retry_after: float = attrs.field(default=0.0)
216    """The amount of seconds you need to wait before retrying to requests."""
217
218    message: str = attrs.field(init=False)
219    """A Bungie human readable message describes the cause of the error."""
220
221    @message.default  # type: ignore
222    def _(self) -> str:
223        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
224
225    def __str__(self) -> str:
226        return self.message

Raised when being hit with ratelimits.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
@typing.final
class RecordState(aiobungie.Flag):
48@typing.final
49class RecordState(enums.Flag):
50    """An enum for records component states."""
51
52    NONE = 0
53    REDEEMED = 1 << 0
54    UNAVAILABLE = 1 << 1
55    OBJECTIVE_NOT_COMPLETED = 1 << 2
56    OBSCURED = 1 << 3
57    INVISIBLE = 1 << 4
58    ENTITLEMENT_UNOWNED = 1 << 5
59    CAN_EQUIP_TITLE = 1 << 6

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
688@typing.final
689class Relationship(int, Enum):
690    """An enum for bungie friends relationship types."""
691
692    UNKNOWN = 0
693    FRIEND = 1
694    INCOMING_REQUEST = 2
695    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
222class RequestMethod(str, enums.Enum):
223    """HTTP request methods enum."""
224
225    GET = "GET"
226    """GET methods."""
227    POST = "POST"
228    """POST methods."""
229    PUT = "PUT"
230    """PUT methods."""
231    PATCH = "PATCH"
232    """PATCH methods."""
233    DELETE = "DELETE"
234    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
195@attrs.define(auto_exc=True)
196class ResponseError(HTTPException):
197    """Standard HTTP responses exception."""

Standard HTTP responses exception.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
@typing.final
class Stat(builtins.int, aiobungie.Enum):
515@typing.final
516class Stat(int, Enum):
517    """An Enum for Destiny 2 character stats."""
518
519    NONE = 0
520    MOBILITY = 2996146975
521    RESILIENCE = 392767087
522    RECOVERY = 1943323491
523    DISCIPLINE = 1735777505
524    INTELLECT = 144602215
525    STRENGTH = 4244567218
526    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
630@typing.final
631class TierType(int, Enum):
632    """An enum for a Destiny 2 item tier type."""
633
634    UNKNOWN = 0
635    CURRENCY = 1
636    BASIC = 2
637    COMMON = 3
638    RARE = 4
639    SUPERIOR = 5
640    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
740@typing.final
741class TransferStatus(Flag):
742    """An enum for items transfer statuses."""
743
744    CAN_TRANSFER = 0
745    """The item can be transferred."""
746    IS_EQUIPPED = 1 << 0
747    """You can't transfer since the item is equipped."""
748    NOT_TRASNFERRABLE = 1 << 1
749    """This item can not be transferred."""
750    COULD_BE_TRANSFERRED = 1 << 2
751    """You can trasnfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can trasnfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
UNDEFINED = UNDEFINED
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
138@attrs.define(auto_exc=True)
139class Unauthorized(HTTPException):
140    """Unauthorized access."""
141
142    http_status: http.HTTPStatus = attrs.field(
143        default=http.HTTPStatus.UNAUTHORIZED, init=False
144    )

Unauthorized access.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
UndefinedOr = typing.Union[aiobungie.UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

UndefinedType()
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
240@typing.final
241class Vendor(int, Enum):
242    """An Enum for all available vendors in Destiny 2."""
243
244    ZAVALA = 69482069
245    XUR = 2190858386
246    BANSHE = 672118013
247    SPIDER = 863940356
248    SHAXX = 3603221665
249    KADI = 529635856
250    """Postmaster exo."""
251    YUNA = 1796504621
252    """Asia servers only."""
253    EVERVERSE = 3361454721
254    AMANDA = 460529231
255    """Amanda holiday"""
256    CROW = 3611983588
257    HAWTHORNE = 3347378076
258    ADA1 = 350061650
259    DRIFTER = 248695599
260    IKORA = 1976548992
261    SAINT = 765357505
262    """Saint-14"""
263    ERIS_MORN = 1616085565
264    SHAW_HAWN = 1816541247
265    """COSMODROME Guy"""
266    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
529@typing.final
530class WeaponType(int, Enum):
531    """Enums for The three Destiny Weapon Types"""
532
533    NONE = 0
534    KINETIC = 1498876634
535    ENERGY = 2465295065
536    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> aiobungie.Iterator[~Item]:
559def into_iter(
560    iterable: collections.Iterable[Item],
561) -> Iterator[Item]:
562    """Transform an iterable into an flat iterator.
563
564    Example
565    -------
566    ```py
567    sequence = [1,2,3]
568    for item in aiobungie.into_iter(sequence).reversed():
569        print(item)
570    # 3
571    # 2
572    # 1
573    ```
574
575    Parameters
576    ----------
577    iterable: `typing.Iterable[Item]`
578        The iterable to convert.
579
580    Raises
581    ------
582    `StopIteration`
583        If no elements are left in the iterator.
584    """
585    return Iterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = [1,2,3]
for item in aiobungie.into_iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> aiobungie.AiobungieError:
229async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
230    """Generates and raise exceptions on error responses."""
231
232    # Not a JSON response, raise immediately.
233
234    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
235    # request with a dummy access token. I can't really do anything about this..
236    if response.content_type != "application/json":
237        return HTTPError(
238            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
239            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
240        )
241
242    body = await response.json()
243    message: str = body.get("Message", "UNDEFINED_MESSAGE")
244    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
245    message_data: dict[str, str] = body.get("MessageData", {})
246    throttle_seconds: int = body.get("ThrottleSeconds", 0)
247    error_code: int = body.get("ErrorCode", 0)
248
249    # Standard HTTP status.
250    if response.status == http.HTTPStatus.NOT_FOUND:
251        return NotFound(
252            message=message,
253            error_code=error_code,
254            throttle_seconds=throttle_seconds,
255            url=str(response.real_url),
256            body=body,
257            headers=response.headers,
258            error_status=error_status,
259            message_data=message_data,
260        )
261
262    elif response.status == http.HTTPStatus.FORBIDDEN:
263        return Forbidden(
264            message=message,
265            error_code=error_code,
266            throttle_seconds=throttle_seconds,
267            url=str(response.real_url),
268            body=body,
269            headers=response.headers,
270            error_status=error_status,
271            message_data=message_data,
272        )
273
274    elif response.status == http.HTTPStatus.UNAUTHORIZED:
275        return Unauthorized(
276            message=message,
277            error_code=error_code,
278            throttle_seconds=throttle_seconds,
279            url=str(response.real_url),
280            body=body,
281            headers=response.headers,
282            error_status=error_status,
283            message_data=message_data,
284        )
285
286    elif response.status == http.HTTPStatus.BAD_REQUEST:
287        # Membership needs to be alone.
288        if error_status == "InvalidParameters":
289            return MembershipTypeError(
290                message=message,
291                body=body,
292                headers=response.headers,
293                url=str(response.url),
294                membership_type=message_data["membershipType"],
295                required_membership=message_data["membershipInfo.membershipType"],
296                membership_id=int(message_data["membershipId"]),
297            )
298        return BadRequest(
299            message=message,
300            body=body,
301            headers=response.headers,
302            url=str(response.url),
303        )
304
305    status = http.HTTPStatus(response.status)
306
307    if 400 <= status < 500:
308        return ResponseError(
309            message=message,
310            error_code=error_code,
311            throttle_seconds=throttle_seconds,
312            url=str(response.real_url),
313            body=body,
314            headers=response.headers,
315            error_status=error_status,
316            message_data=message_data,
317            http_status=status,
318        )
319
320    # Need to self handle ~5xx errors
321    elif 500 <= status < 600:
322        # No API key or method requires OAuth2 most likely.
323        if error_status in {
324            "ApiKeyMissingFromRequest",
325            "WebAuthRequired",
326            "ApiInvalidOrExpiredKey",
327            "AuthenticationInvalid",
328            "AuthorizationCodeInvalid",
329        }:
330            return Unauthorized(
331                message=message,
332                error_code=error_code,
333                throttle_seconds=throttle_seconds,
334                url=str(response.real_url),
335                body=body,
336                headers=response.headers,
337                error_status=error_status,
338                message_data=message_data,
339            )
340
341        # Anything contains not found.
342        elif (
343            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
344        ):
345            return NotFound(
346                message=message,
347                error_code=error_code,
348                throttle_seconds=throttle_seconds,
349                url=str(response.real_url),
350                body=body,
351                headers=response.headers,
352                error_status=error_status,
353                message_data=message_data,
354            )
355
356        # Other 5xx errors.
357        else:
358            return InternalServerError(
359                message=message,
360                error_code=error_code,
361                throttle_seconds=throttle_seconds,
362                url=str(response.real_url),
363                body=body,
364                headers=response.headers,
365                error_status=error_status,
366                message_data=message_data,
367                http_status=status,
368            )
369    # Something else.
370    else:
371        return HTTPException(
372            message=message,
373            error_code=error_code,
374            throttle_seconds=throttle_seconds,
375            url=str(response.real_url),
376            body=body,
377            headers=response.headers,
378            error_status=error_status,
379            message_data=message_data,
380            http_status=status,
381        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
384def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
385    return (
386        "{ \n"
387        + "\n".join(  # noqa: W503
388            f"{f'   {key}'}: {value}"
389            if key not in ("Authorization", "X-API-KEY")
390            else f"   {key}: HIDDEN_TOKEN"
391            for key, value in headers.items()
392        )
393        + "\n}"  # noqa: W503
394    )